Перейти к основному содержанию
Рецепты Linux

Main navigation

  • Основы
  • Система
  • Команды
  • Программы
  • Дистро
  • Интерфейсы
  • Устройства
  • Доки
User account menu
  • Войти

Строка навигации

  1. Главная
  2. Pro Git
  3. Ветвление в Git

Основы ветвления и слияния

Давайте рассмотрим простой пример ветвления и слияния с таким процессом работы, который вы могли бы использовать в настоящей разработке. Вы будете делать следующее:
  1. Работать над веб-сайтом.
  2. Создадите ветку для новой истории, над которой вы работаете.
  3. Выполните некоторую работу на этой ветке.
На этом этапе вы получите звонок о том, что сейчас критична другая проблема, и её надо срочно решить. Вы сделаете следующее:
  1. Вернётесь на производственную ветку.
  2. 2. Создадите ветку для исправления ошибки.
  3. После его тестирования, сольёте ветку с исправлением и отправите в продакшн.
  4. Переключитесь к прерванной истории и продолжите работу.

Основы ветвления

Для начала представим, что вы работаете над своим проектом и уже имеете пару коммитов (см. Рисунок 3-10).

Короткая и простая история коммитов
Рисунок 3-10. Рисунок 3-10.

Вы решили, что вы будете работать над проблемой №53 из системы отслеживания ошибок, используемой вашей компанией. Разумеется, Git не привязан к какой-то определенной системе отслеживания ошибок. Просто из-за того, что проблема №53 является основной задачей, над которой вы хотите работать, вы создадите новую ветку для работы в ней. Чтобы создать ветку и сразу же перейти на неё, вы можете выполнить команду git checkout с ключом -b: $ git checkout -b iss53 Switched to a new branch "iss53" Это сокращение для: $ git branch iss53 $ git checkout iss53 Рисунок 3-11 показывает результат.

Создание новой ветки / указателя
Рисунок 3-11. Создание новой ветки / указателя

Во время работы над вашим веб-сайтом, вы делаете несколько коммитов. Эти действия сдвигают ветку iss53 вперёд потому, что вы на неё перешли (то есть ваш HEAD указывает на неё; см. Рисунок 3-12): $ vim index.html $ git commit -a -m 'added a new footer [issue 53]'

Ветка iss53 передвинулась вперёд во время работы
Рисунок 3-12. Ветка iss53 передвинулась вперёд во время работы

Теперь вы получаете звонок о том, что есть проблема с веб-сайтом, которую необходимо немедленно устранить. С Git, вам нет нужды создавать заплатку вместе с теми изменениями, которые вы уже сделали для iss53. А также не надо прикладывать много усилий, чтобы отменить эти изменения перед тем, как вы сможете начать работать над решением срочной проблемы. Всё, что вам нужно сделать, это перейти на ветку master. Однако, прежде чем сделать это, учтите, что если в вашем рабочем каталоге или индексе имеются незафиксированные изменения, которые конфликтуют с веткой, на которую вы переходите, Git не позволит переключить ветки. Лучше всего при переключении веток иметь чистое рабочее состояния. Существует несколько способов добиться этого (а именно, прятанье (stash) работы и правка (amend) коммита), которые мы рассмотрим позже. А на данный момент представим, что вы зафиксировали все изменения, и можете переключиться обратно на ветку master: $ git checkout master Switched to branch "master" Теперь рабочий каталог проекта находится точно в таком же состоянии, что и в момент начала работы над проблемой №53, так что вы можете сконцентрироваться на срочном изменении. Очень важно запомнить: Git возвращает ваш рабочий каталог к снимку состояния того коммита, на который указывает ветка, на которую вы переходите. Он добавляет, удаляет и изменяет файлы автоматически, чтобы гарантировать, что состояние вашей рабочей копии идентично последнему коммиту на ветке. Итак, вам надо срочно исправить ошибку. Давайте создадим для этого ветку, на которой вы будете работать (см. Рисунок 3-13): $ git checkout -b 'hotfix' Switched to a new branch "hotfix" $ vim index.html $ git commit -a -m 'fixed the broken email address' [hotfix]: created 3a0874c: "fixed the broken email address" 1 files changed, 0 insertions(+), 1 deletions(-)

Ветка для решения срочной проблемы базируется на ветке master
Рисунок 3-13. Ветка для решения срочной проблемы базируется на ветке master

Вы можете запустить тесты, убедиться, что решение работает, и слить (merge) изменения назад в ветку master, чтобы включить его в продукт. Это делается с помощью команды git merge: $ git checkout master $ git merge hotfix Updating f42c576..3a0874c Fast forward README | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) Наверное, вы заметили фразу “Fast forward” в этом слиянии. Так как ветка, которую вы сливали, указывала на коммит, являющийся прямым потомком коммита, на котором вы находитесь, Git передвигает указатель вперёд. Иными словами, когда вы пытаетесь слить один коммит с другим, который может быть достигнут идя по истории первого коммита, Git упрощает вещи, перемещая указатель вперёд, так как нету расходящихся изменений для слияния их воедино. Это называется “fast forward” (перемотка). Ваши изменения теперь в снимке состояния коммита, на который указывает ветка master, и вы можете включить изменения в продукт (см. Рисунок 3-14).

После слияния ветка master указывает туда же, куда и ветка hotfix
Рисунок 3-14. После слияния ветка master указывает туда же, куда и ветка hotfix

После того, как очень важная проблема решена, вы готовы вернуться обратно к работе, которую делали, прежде чем были прерваны. Однако, сначала удалите ветку hotfix, так как она больше не нужна — ветка master уже указывает на то же место. Вы можете удалить ветку с помощью опции -d к git branch: $ git branch -d hotfix Deleted branch hotfix (3a0874c). Теперь вы можете вернуться обратно к рабочей ветке для проблемы №53 и продолжить работать над ней (см. Рисунок 3-15): $ git checkout iss53 Switched to branch "iss53" $ vim index.html $ git commit -a -m 'finished the new footer [issue 53]' [iss53]: created ad82d7a: "finished the new footer [issue 53]" 1 files changed, 1 insertions(+), 0 deletions(-)

Ветка iss53 может двигаться вперёд независимо
Рисунок 3-15. Ветка iss53 может двигаться вперёд независимо

Стоит напомнить, что работа, сделанная на ветке hotfix, не включена в файлы на ветке iss53. Если вам это необходимо, вы можете выполнить слияние ветки master в ветку iss53 посредством команды git merge master. Или же вы можете подождать с интеграцией изменений до тех пор, пока не решите включить изменения на iss53 в продуктовую ветку master.

Основы слияния

Представьте себе, что вы разобрались с проблемой №53 и готовы объединить эту ветку и свой master. Чтобы сделать это, вы выполните слияние вашей ветки iss53 в ветку master точно так же, как делали ранее с веткой hotfix. Все что вы должны сделать ― перейти на ту ветку, в которую вы хотите внести свои изменения и выполнить команду git merge: $ git checkout master $ git merge iss53 Merge made by recursive. README | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) Сейчас слияние выглядит немного не так, как для ветки hotfix, которое вы делали ранее. В данном случае ваша история разработки разделилась в некоторой точке. Так как коммит на той ветке, на которой вы находитесь, не является прямым предком для ветки, которую вы сливаете, Git-у придётся проделать кое-какую работу. В этом случае Git делает простое трехходовое слияние, используя при этом два снимка состояния репозитория, на которые указывают вершины веток, и общий снимок-прародитель для этих двух веток. На рисунке 3-16 выделены три снимка, которые Git будет использовать для слияния в этом случае.

Git автоматически определяет наилучшего общего предка для слияния веток
Рисунок 3-16. Git автоматически определяет наилучшего общего предка для слияния веток

Вместо того, чтобы просто передвинуть указатель ветки вперёд, Git создаёт новый снимок состояния, который является результатом трехходового слияния, и автоматически создает новый коммит, который указывает на этот новый снимок состояния (смотри Рисунок 3-17). Такой коммит называют коммит-слияние, так как он является особенным из-за того, что имеет больше одного предка. Стоит отметить, что Git определяет наилучшего общего предка для слияния веток; в CVS или Subversion (версии ранее 1.5) этого не происходит. Разработчик должен сам указать основу для слияния. Это делает слияние в Git гораздо более простым занятием, чем в других системах.

Git автоматически создает новый коммит, содержащий результаты слияния
Рисунок 3-17. Git автоматически создает новый коммит, содержащий результаты слияния

Теперь, когда вы осуществили слияние ваших наработок, ветка iss53 вам больше не нужна. Можете удалить ее и затем вручную закрыть карточку (ticket) в вашей системе: $ git branch -d iss53

Основы конфликтов при слиянии

Иногда процесс слияния не идет гладко. Если вы изменили одну и ту же часть файла по-разному в двух ветках, которые собираетесь объединить, Git не сможет сделать это чисто. Если ваше решение проблемы №53 изменяет ту же часть файла, что и hotfix, вы получите конфликт слияния, и выглядеть он будет примерно следующим образом: $ git merge iss53 Auto-merging index.html CONFLICT (content): Merge conflict in index.html Automatic merge failed; fix conflicts and then commit the result. Git не создал новый коммит для слияния. Он приостановил этот процесс до тех пор, пока вы не разрешите конфликт. Если вы хотите посмотреть, какие файлы не прошли слияние (на любом этапе после возникновения конфликта), можете выполнить команду git status: [master*]$ git status index.html: needs merge # On branch master # Changed but not updated: # (use "git add ..." to update what will be committed) # (use "git checkout -- ..." to discard changes in working directory) # # unmerged: index.html # Всё, что имеет отношение к конфликту слияния и что не было разрешено, отмечено как unmerged. Git добавляет стандартные маркеры к файлам, которые имеют конфликт, так что вы можете открыть их вручную и разрешить эти конфликты. Ваш файл содержит секцию, которая выглядит примерно так: HEAD:index.html
contact : email.support@github.com
=======
please contact us at support@github.com
>>>>>>> iss53:index.html
В верхней части блока (всё что выше =======) это версия из HEAD (вашей ветки master, так как именно на неё вы перешли перед выполнением команды merge), всё что находится в нижней части ― версия в iss53. Чтобы разрешить конфликт вы должны либо выбрать одну из этих частей, либо как-то объединить содержимое по своему усмотрению. Например, вы можете разрешить этот конфликт заменой всего блока, показанного выше, следующим блоком:
please contact us at email.support@github.com
Это решение содержит понемногу из каждой части, и я полностью удалил строки , ======= и >>>>>>>. После того, как вы разрешили каждую из таких секций с каждым из конфликтных файлов, выполните git add для каждого конфликтного файла. Индексирование будет означать для Git, что все конфликты в файле теперь разрешены. Если вы хотите использовать графические инструменты для разрешения конфликтов, можете выполнить команду git mergetool, которая запустит соответствующий графический инструмент и покажет конфликтные ситуации: $ git mergetool merge tool candidates: kdiff3 tkdiff xxdiff meld gvimdiff opendiff emerge vimdiff Merging the files: index.html Normal merge conflict for 'index.html': {local}: modified {remote}: modified Hit return to start merge resolution tool (opendiff): Если вы хотите использовать другой инструмент для слияния, нежели выбираемый по умолчанию (Git выбрал opendiff для меня, так как я выполнил команду на Mac). Вы можете увидеть все поддерживаемые инструменты, указанные выше после “merge tool candidates”. Укажите название предпочтительного для вас инструмента. В Главе Настройка Git мы обсудим, как изменить это значение по умолчанию для вашего окружения. После того, как вы выйдете из инструмента для выполнения слияния, Git спросит вас, было ли оно успешным. Если вы отвечаете, что да ― файл индексируется (добавляется в область для коммита), чтобы дать вам понять, что конфликт разрешен. Можете выполнить git status ещё раз, чтобы убедиться, что все конфликты были разрешены: $ git status # On branch master # Changes to be committed: # (use "git reset HEAD ..." to unstage) # # modified: index.html # Если вы довольны тем, что получили, и удостоверились, что всё, имевшее конфликты, было проиндексировано, можете выполнить git commit для завершения слияния. По умолчанию сообщение коммита будет выглядеть примерно так: Если вы довольны тем, что получили, и удостоверились, что всё, имевшее конфликты, было проиндексировано, можете выполнить git commit для завершения слияния. По умолчанию сообщение коммита будет выглядеть примерно так: Вы можете дополнить это сообщение информацией о том, как вы разрешили конфликт, если считаете, что это может быть полезно для других в будущем. Например, можете указать почему вы сделали то, что сделали, если это не очевидно конечно. Pro Git

Перекрёстные ссылки книги для Основы ветвления и слияния

  • Что такое Ветвь
  • Вверх
  • Управление ветками

Book navigation

  • Введение
  • Основы Git
  • Ветвление в Git
    • Что такое Ветвь
    • Основы ветвления и слияния
    • Управление ветками
    • Приемы работы с ветками
    • Удалённые ветки
    • Перемещение
    • Резюме
  • Git на сервере
  • Распределённый Git
  • Инструменты Git

Последние материалы

  • Приложение scanimage
    1 day ago
  • Утилита sensors
    5 days ago
  • Сканер Rkhunter
    1 week 5 days ago
  • Программа resize2fs
    2 weeks 3 days ago
  • Аудиопроигрыватель QMMP
    3 weeks 2 days ago
RSS feed

Secondary menu

  • О проекте

© 2008–2025 Олег Меньшенин mensh@yandex.ru