Использование веток

Git merge

 

Команда git merge отвечает за объединение ветвлений в истории Git и позволяет выполнять слияние отдельных процессов разработки, созданных с помощью команды git branch, в единую ветку.

Обратите внимание: все приведенные ниже команды выполняют слияние в текущую ветку, в то время как целевая ветка остается без изменений. Поэтому git merge часто используется в сочетании с командами git checkout (выбор текущей ветки) и git branch -d (удаление целевой устаревшей ветки).

Порядок действий

Команда git merge объединяет несколько последовательностей коммитов в общую историю. Чаще всего с помощью команды git merge объединяют две ветки. Подобный метод слияния рассматривается в примерах ниже. В таких случаях команда git merge берет два указателя на коммиты (обычно последние) и находит общий для них родительский коммит. Затем Git создает «коммит слияния», в котором сочетаются изменения из обеих последовательностей, выбранных к слиянию.

Представим, что у нас есть новая функциональная ветка, которая отходит от основной (master). Нам нужно объединить функциональную ветку с master.

При запуске этой команды произойдет слияние указанной функциональной ветки с текущей — в данном случае это master. Git автоматически определяет алгоритм слияния (подробнее см. ниже).

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

Подготовка к слиянию

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

Проверка выбора принимающей ветки

Выполните команду git status. Это позволит убедиться, что HEAD указывает на ветку, принимающую результаты слияния. При необходимости выполните команду git checkout <receiving>, чтобы переключиться на принимающую ветку. Для примера выполним команду git checkout master.

Получение последних коммитов из удаленного репозитория

Убедитесь, что в принимающей ветке и ветке для слияния содержатся последние изменения из удаленного репозитория. Выполните команду git fetch, чтобы получить из него последние коммиты. Затем убедитесь, что в ветке master также содержатся последние изменения. Для этого можно выполнить команду git pull.

Выполнение слияния

После указанных выше действий по подготовке можете приступать к слиянию. Для этого выполните команду git merge <branch name>, где <branch name> — название ветки, которая будет объединена с принимающей.

Ускоренное слияние

Ускоренное слияние происходит, когда последний коммит текущей ветки является прямым продолжением целевой ветки. В этом случае для объединения истории Git не выполняет полноценное слияние, а просто переносит последний коммит текущей ветки в конец целевой ветки. Объединение историй проходит успешно, поскольку все коммиты целевой ветки теперь доступны в текущей. Так, ускоренное слияние одной из функций с master будет выглядеть следующим образом:

Однако выполнить ускоренное слияние не получится, если ветки после разделения развивались независимо друг от друга. Если до целевой ветки нет прямого пути, Git будет вынужден объединить их методом трехстороннего слияния. Такое слияние выполняется с помощью специального коммита, который служит для объединения двух историй. Метод называется трехсторонним, поскольку Git использует три коммита для создания коммита слияния (последние коммиты двух веток и общий родительский элемент).


Обе стратегии слияния эффективны в работе. При этом многие разработчики предпочитают метод ускоренного слияния (достигается за счет перебазирования) для незначительных функций или исправлений ошибок, в то время как трехстороннее слияние используется для включения функций с продолжительным временем разработки. В последнем случае коммит слияния служит местом соединения двух веток.

В первом примере демонстрируется ускоренное слияние. С помощью кода создается новая ветка, после чего в нее добавляется два коммита. Затем она включается в основную ветку посредством ускоренного слияния.

# Создание новой функциональной ветки
git checkout -b new-feature master
# Edit some files
git add <file>
git commit -m "Start a feature"
# Редактирование файлов
git add <file>
git commit -m "Finish a feature"
# Слияние ветки new-feature
git checkout master
git merge new-feature
git branch -d new-feature

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

Обратите внимание, что теперь Git сможет без проблем выполнить команду git branch -d, поскольку ветка new-feature теперь напрямую связана с основной.

Если при ускоренном слиянии вам понадобится доступ к коммиту слияния для учета изменений, вы сможете выполнить команду git merge с опцией --no-ff.

git merge --no-ff <branch>

Эта команда выполнит объединение указанной ветки с текущей с обязательным созданием коммита слияния (даже если слияние будет ускоренным). Это полезно для учета всех слияний в репозитории.

Трехстороннее слияние

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

# Создание новой функциональной ветки
git checkout -b new-feature master
# Редактирование файлов
git add <file>
git commit -m "Start a feature"
# Редактирование файлов
git add <file>
git commit -m "Finish a feature"
# Разработка ветки master
git checkout master
# Редактирование файлов
git add <file>
git commit -m "Make some super-stable changes to master"
# Слияние ветки new-feature
git merge new-feature
git branch -d new-feature

Обратите внимание, что Git не может выполнить ускоренное слияние. Это происходит, поскольку невозможно перенести указатель master на ветку new-feature без использования предыдущих коммитов.

В большинстве случаев ветка new-feature отводится под более объемные функции с продолжительным временем разработки, за которое в ветке master появляются новые коммиты. Если бы реальный размер вашей функциональной ветки был так же мал, как в примере выше, было бы проще перебазировать ее на ветку master и выполнить ускоренное слияние. В этом случае не потребовалось бы засорять историю проектов лишними коммитами слияния.

Разрешение конфликтов

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

Преимущество слияния в Git заключается в том, что разрешение конфликтов проходит по привычной схеме «изменение — подготовка — коммит». При обнаружении конфликта выполните команду git status, чтобы увидеть, какие файлы необходимо исправить. Так, если в обеих ветках изменена одна и та же часть файла hello.py, вы увидите следующее:

On branch master
Unmerged paths:
(use "git add/rm ..." as appropriate to mark resolution)
both modified: hello.py

Представление конфликтов

Когда Git обнаруживает конфликт в ходе слияния, к затронутым файлам добавляются визуальные индикаторы по обе стороны проблемного содержимого: <<<<<<<, ======= и >>>>>>>. Чтобы обнаружить конфликты, попробуйте поискать в проекте эти индикаторы.

контент, не затронутый конфликтом
<<<<<<< master
конфликтующий код из ветки master
=======
конфликтующий код из ветки feature
>>>>>>> feature branch;

Обычно содержимое перед отметкой ======= относится к принимающей ветке, а все, что указано после нее — к ветке, для которой выполняется слияние.

После обнаружения конфликтующих участков кода вы можете исправить их по своему усмотрению. Когда вы будете готовы завершить слияние, выполните команду git add на конфликтующем файле или файлах — так вы сообщите Git, что конфликт разрешен. Затем запустите обычную команду git commit, чтобы создать коммит слияния. Поскольку процесс ничем не отличается от фиксирования обычного снимка состояния, рядовому разработчику не составит труда разрешить конфликты при слиянии.

Обратите внимание, что конфликты возможны только в процессе трехстороннего слияния и не могут возникать при ускоренном слиянии. 

Резюме

В этом документе содержится сводная информация о команде git merge. Слияние — необходимый инструмент для работы в Git. Мы познакомились с принципами его работы, а также обсудили различия между ускоренным и полноценным трехсторонним слиянием. Ниже перечислены основные моменты:
 

  1. При слиянии в Git последовательности коммитов объединяются в общую историю.
  2. В основном Git выполняет объединение двумя способами: ускоренным и трехсторонним слиянием.
  3. Если в обеих последовательностях коммитов нет конфликтующих изменений, Git объединит их автоматически.

В документе также упоминались другие команды Git: git branch, git pull и git fetch. Подробные сведения о них см. на соответствующих страницах. 

Готовы попробовать создать ответвление?

Ознакомьтесь с этим интерактивным обучающим руководством.

Начните прямо сейчас