W3docs

git merge

На этой странице вы найдёте информацию о команде git merge, принципах её работы и различии между fast-forward и трёхсторонним слиянием.

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

На этой странице рассматривается, что происходит во время слияния, в чём разница между fast-forward и 3-сторонним слиянием, как принудительно создать коммит слияния и как распознать и разрешить конфликт слияния.

Команда тесно связана с git branch (для создания и удаления веток), git checkout (для переключения на принимающую ветку) и git pull (для обновления перед слиянием). Если вы предпочитаете линейную историю без коммитов слияния, рассмотрите git rebase как альтернативу.

Принцип работы

Основное применение git merge — объединение двух веток. Команда также используется для интеграции нескольких коммитов из одной ветки в другую. На следующей иллюстрации git merge берёт вершины двух веток и находит общий предковый коммит между ними. Этот общий базовый коммит используется для создания нового коммита слияния, объединяющего изменения из обеих веток. Здесь у нас две ветки: master и stage. Нам нужно слить ветку stage в ветку master.

gitmerge

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

gitmerge1

Процесс слияния

Перед началом слияния выполните следующие шаги:

  • Убедитесь, что вы находитесь на правильной принимающей ветке. Выполните git checkout <receiving branch> для переключения на неё.
  • Обновите целевую ветку последними удалёнными изменениями. Выполните git pull, чтобы загрузить и интегрировать последние удалённые коммиты.
  • Последний шаг — выполнить git merge <branch name>, указав ветку, которую нужно слить в принимающую ветку.

Fast-forward слияние

Fast-forward слияние происходит, когда путь от текущей ветки до целевой является линейным. При fast-forward слиянии истории объединяются, поскольку все коммиты, достижимые из целевой ветки, доступны через текущую ветку. Вот пример fast-forward слияния:

gitmerge2

Когда две истории расходятся, Git использует трёхстороннее слияние в качестве альтернативы. 3-стороннее слияние использует специальный коммит для объединения двух историй.

gitmerge3

Fast-forward слияния, как правило, используются для небольших функций или исправлений ошибок, тогда как 3-сторонние слияния применяются для интеграции долгосрочных функций. В следующих примерах используется fast-forward слияние:

git merge

# Start the stage
git checkout -b stage master
# Edit some files
git add <file>
git commit -m "Start with the stage"
# Edit some files
git add <file>
git commit -m "Finish with the stage"
# Merge in the stage branch
git checkout master
git merge stage
git branch -d stage

Мы выполняем git branch -d, чтобы удалить ветку stage, поскольку теперь она доступна из ветки master.

Команда git merge с опцией --no-ff используется, если при fast-forward слиянии требуется создать коммит слияния: она сливает указанную ветку в текущую, всегда создавая коммит слияния (даже при возможности fast-forward):

git merge --no-ff

git merge --no-ff <branch>

3-стороннее слияние

Этот сценарий требует трёхстороннего слияния, когда ветка master продвигается вперёд, пока ветка stage ещё в разработке. Это используется, когда члены команды одновременно работают над крупной функциональностью:

the git merge command

# Start the stage
git checkout -b stage master
# Edit some files
git add <file>
git commit -m "Start with the stage"
# Edit some files
git add <file>
git commit -m "Finish with the stage"
# Develop the master branch
git checkout master
# Edit some files
git add <file>
git commit -m "Make some super-stable changes to master"
# Merge in the stage branch
git merge stage
git branch -d stage

В приведённом примере stage — крупная функциональность, на разработку которой уходит много времени, поэтому мы используем трёхстороннее слияние. Если ваша функциональность небольшая, лучше воспользоваться fast-forward слиянием, чтобы не засорять историю проекта лишними коммитами.

Полезные опции слияния

Эти флаги изменяют поведение git merge:

ОпцияЧто делает
--no-ffВсегда создаёт коммит слияния, даже если возможен fast-forward. Сохраняет видимость ветки функциональности в истории.
--ff-onlyВыполняет слияние только если возможен fast-forward; иначе прерывает. Полезно в скриптах для отказа от коммита слияния.
--squashОбъединяет все коммиты из ветки в единый набор подготовленных изменений (затем вы делаете коммит вручную). Коммит слияния и второй родитель не создаются.
--abortОстанавливает конфликтное слияние и восстанавливает ветку в состояние до слияния.
-m "<msg>"Задаёт сообщение коммита слияния напрямую, не открывая редактор.

Squash-слияние удобно, когда ветка функциональности содержит много небольших коммитов «в процессе работы», которые не нужны в основной истории:

git merge --squash

git checkout master
git merge --squash stage
git commit -m "Add stage feature"

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

При слиянии двух веток, если одна и та же часть одного и того же файла изменена в обеих ветках, возникают конфликты слияния, поскольку Git не может определить, какую версию использовать. В этом случае Git останавливается перед созданием коммита слияния, чтобы вы могли разрешить конфликт. Процесс слияния в Git использует рабочий процесс редактирование/добавление в индекс/коммит для разрешения конфликтов. При возникновении конфликта команда git status покажет файлы, требующие разрешения. Следующая картина отобразится, если одни и те же части файла example.txt были изменены:

git status

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

Если вы решили не продолжать слияние, вы можете отменить его в любой момент, выполнив git merge --abort.

Как представлены конфликты

В случае конфликтов Git редактирует содержимое затронутых файлов, добавляя визуальные маркеры с обеих сторон конфликтующего содержимого. Конфликты могут возникать только при трёхстороннем слиянии — fast-forward слияние никогда не порождает конфликтов, так как принимающая ветка не имеет собственных новых коммитов, способных столкнуться с входящими изменениями.

Основные маркеры — <<<<<<<, ======= и >>>>>>>. Они помогают найти конфликтующие секции в файлах.

git conflicts

here is some content not affected by the conflict
<<<<<<< master
this is conflicted text from master
=======
this is conflicted text from stage branch
>>>>>>> stage

Чтобы разрешить конфликт, откройте файл, удалите три строки с маркерами (<<<<<<<, =======, >>>>>>>), и отредактируйте оставшийся текст до нужной вам версии. Затем выполните git add <file> для конфликтующего файла, чтобы отметить его как разрешённый, и запустите git commit для создания коммита слияния.

Полный рабочий пример

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

reproduce a conflict and resolve it

git init demo && cd demo
echo "line one" > file.txt
git add file.txt
git commit -m "Initial commit"

# Create a branch and change the line there
git checkout -b stage
echo "change from stage" > file.txt
git commit -am "Edit on stage"

# Change the same line on master
git checkout master
echo "change from master" > file.txt
git commit -am "Edit on master"

# Merge stage into master -> conflict
git merge stage
# Auto-merging file.txt
# CONFLICT (content): Merge conflict in file.txt
# Automatic merge failed; fix conflicts and then commit the result.

После редактирования file.txt и сохранения нужной версии завершите слияние:

git add file.txt
git commit -m "Merge stage, keep resolved line"
git branch -d stage

Проверка слияния

После слияния убедитесь в корректности результата с помощью git log. Флаги --graph и --oneline отображают топологию веток, что позволяет легко найти коммит слияния (с двумя родителями):

git log --oneline --graph

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

Практика

Практика
What are the key features and processes involved in the 'git merge' command?
What are the key features and processes involved in the 'git merge' command?
Was this page helpful?