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

Рассмотрите простой пример рабочего процесса, который может быть полезен в вашем проекте.

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

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

Предположим, вы работаете над проектом и уже имеете несколько коммитов.

Вы решаете, что теперь вы будете заниматься задачей №53 из вашей системы проектирования. В панели Навигатор вы нажимаете Групповая разработка > Создать новую ветку..., создаете ветку feature/issue-53 и сразу переключаетесь на нее.

Вы работаете над новой функциональностью и фиксируете изменения. Это приводит к тому, что ветка feature/issue-53 движется вперед, так как вы переключились на нее ранее (HEAD указывает на нее).

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

Благодаря Git вам не придется ни пытаться реализовать исправление вместе с изменениями, которые вы сделали в ходе разработки feature/issue-53. Вам даже не придется прилагать усилий, чтобы откатить все эти изменения для начала работы над исправлением. Все, что вам нужно, это переключиться на ветку master.

Имейте в виду, что если рабочий каталог или индекс содержат незафиксированные изменения, конфликтующие с веткой, на которую вы хотите переключиться, то Git не позволит переключить ветки. Лучше всего переключаться из чистого рабочего состояния проекта: все измененные файлы добавить в индекс и сделать коммит. Есть способы обойти это (припрятать изменения (stash) или добавить их в последний коммит (amend)). Теперь предположим, что вы зафиксировали все свои изменения и можете переключиться на ветку master.

Возможная проблема: Чтобы видеть в панели История все ветки, а не только ветку, на которую указывает HEAD, включите в настройках панели фильтр refs/heads/**.

История вашего репозитория будет выглядеть следующим образом.

С этого момента ваш рабочий каталог имеет точно такой же вид, какой был перед началом работы над задачей №53. Теперь вы можете сосредоточиться на работе над исправлением.

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

Теперь вы можете перейти к написанию исправления. Создайте новую ветку bugfix/bug-135 и исправьте в ней критическую ошибку.

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

Для этого вам сначала нужно переключиться на основную ветку master, а затем влить в нее bugfix/bug-135. Для этого в панели Навигатор нажмите Групповая разработка > Слить... > bugfix/bug-135 в контекстном меню проекта.

Выберите локальную ветку bugfix/bug-135 и нажмите Слить.

В результате вы получите следующее информационное сообщение.

А история коммитов будет выглядеть у вас следующим образом.

Вы заметили фразу «перемотка вперед» (Fast-forward) в информационном сообщении? Из-за того, что коммит, на который указывала ветка, которую вы влили, был прямым потомком того коммита, на котором вы находились, Git просто переместил указатель ветки вперед.

Другими словами, если в коммит вливается тот коммит, до которого можно добраться, двигаясь по истории прямо, Git упрощает слияние, просто перенося указатель метки вперед (так как нет разветвления в работе). Это называется перемотка вперед (fast-forward).

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

После внедрения вашего критического исправления вы готовы вернуться к работе над тем, что были вынуждены отложить. Но сначала нужно удалить ветку bugfix/bug-135, потому что она больше не нужна, ведь ветка master указывает на то же самое место.

Для удаления ветки в панели Навигатор нажмите Групповая разработка > Удалить ветку... > bugfix/bug-135 в контекстном меню проекта. При этом установите флажок Удалить информационную базу ..., т. к. эта база вам больше не понадобится.

После нажатия Готово ваша история будет выглядеть следующим образом:

Теперь вы можете переключить ветку, вернуться к работе над своей задачей № 53 и продолжить работу над ней, сделав еще один коммит.

Стоит обратить внимание на то, что все изменения из ветки bugfix/bug-135 не включены в вашу ветку feature/issue-53. Если их нужно включить, вы можете влить ветку master в вашу ветку feature/issue-53 командой Групповая разработка > Слить... > master, или же вы можете отложить слияние этих изменений до завершения работы и затем переключиться на ветку master и влить ветку feature/issue-53 в master.

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

Предположим, вы решили, что работа по задаче №53 закончена, и ее можно влить в ветку master. Для этого, как вы делали это с веткой bugfix/bug-135 ранее, нужно переключиться на ветку, в которую вы хотите включить изменения (master), и выполнить команду Групповая разработка > Слить... > feature/issue-53 в контекстном меню проекта.

Результат этой операции будет отличаться от результата слияния ветки bugfix/bug-135. Рассмотрите ситуацию подробнее.

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

Вместо того чтобы просто передвинуть указатель ветки вперед, Git создает новый снимок-результат трехстороннего слияния, а затем автоматически делает коммит. Этот особый коммит называют коммитом слияния (merge commit), так как у него более одного предка.

На схеме это будет выглядеть следующим образом.

Стоит отметить, что Git сам определяет наилучшего общего предка, подходящего как база для слияния. Это отличает его от более старых инструментов, таких как CVS или Subversion (до версии 1.5), где разработчикам, выполнявшим слияние, приходилось самим находить лучшую базу. Это безумно упрощает слияние в Git по сравнению с указанными системами.

Теперь, когда работа влита, ветка feature/issue-53 больше не нужна. Вы можете закрыть задачу №53 в системе проектирования, и удалить ветку.

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

Иногда процесс слияния не проходит гладко. Если вы изменили одну и ту же часть одного и того же файла по-разному в двух объединяемых ветках, Git не сможет их чисто объединить. Если ваше исправление ошибки №53 потребовало изменить, например, ту же часть файла, (тот же реквизит и т.д.) что и bugfix/bug-135, 1C:EDT откроет редактор сравнения и объединения:

Git не создал коммит слияния автоматически. Он остановил процесс до тех пор, пока вы не разрешите конфликт.

Например, на картинке видно, что и при исправлении критической ошибки и при разработке задачи в отчет ВзаимосвязьПродажТоваров был добавлен реквизит Реквизит, но разного типа.

После того, как все конфликты разрешены, нажмите Объединить. 1C:EDT выполнит объединение и создаст коммит слияния.

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

По материалам книги Pro Git (авторы Scott Chacon и Ben Straub, издательство Apress). Книга распространяется по лицензии Creative Commons Attribution Non Commercial Share Alike 3.0 license.