Разрешить конфликт при слиянии модулей

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

Конфликт возникает тогда, когда один и тот же элемент приложения был изменен двумя разработчиками или одним и тем же разработчиком, но в разных ветках. В этом случае 1C:EDT не всегда может определить самостоятельно, изменения какого разработчика следует применить.

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

Для создания примера использованы 1C:EDT 2023.3.5 и «1С:Предприятие» 8.3.24.1368.

Выполните подготовительные действия

  1. Запустите 1C:EDT Start;
  2. Создайте новый проект 1C:EDT Start;
  3. Запустите этот проект;
  4. Нажмите Начать работу;
  5. Импортируйте проект из репозитория https://github.com/1C-Company/team-demo-edt2 (возможна ошибка);
  6. Чтобы в дальнейшем вам было удобно наблюдать за результатами, подготовьте рабочее пространство:
    1. Откройте модуль приложения Demo2;
    2. Откройте панель История. Для этого в панели Навигатор нажмите Групповая разработка > Показать Историю в контекстном меню проекта. Панель История всплывет в правом верхнем углу;
    3. Нажмите на значок Восстановить — панель История зафиксируется в нижней части экрана;
    4. В командной панели отожмите кнопку (Связать с редактором), чтобы панель показывала все коммиты, независимо от того, что выделено в панели Навигатор;
    5. Нажмите (Change the File Scope for the History) и выберите вариант фильтрации Все изменения в репозитории, чтобы панель показывала все коммиты;
    6. Нажмите (Change which commits to show) и установите флажок refs/heads/**, чтобы видеть все локальные ветки репозитория.
    7. Извлеките локальную ветку feature. По сути это не обязательно, потому что в локальную ветку master можно влить ветку удаленного отслеживания origin/feature. Но вы извлеките ветку feature локально для наглядности, чтобы пример выглядел так, как будто это ваша ветка, которую вы вливаете в master.
      Для этого переключитесь на ветку удаленного отслеживания origin/feature и затем скажите, что вы хотите создать из нее новую локальную ветку;

Выполните пример

  1. Осмотритесь вокруг. Два разработчика внесли изменения в разные ветки. Вы выступаете в роли Василия, который закончил свою работу, создал 2 коммит и собирается влить свои изменения в master;
  2. Переключитесь на ветку master;
  3. Чтобы влить ветку feature в текущую ветку master в панели Навигатор нажмите Групповая разработка > Слить... в контекстном меню проекта. Вы попробуете два разных способа слияния модулей;
  4. На первый раз выберите локальную ветку feature и больше не меняйте никакие стандартные параметры. Нажмите Слить;
  5. 1C:EDT откроет редактор сравнения и объединения конфигураций. Все уровни иерархии объектов будут свернуты. Чтобы легко развернуть их, установите курсор в первую строку, а затем нажмите и удерживайте клавишу «вправо»;
    В редакторе существует несколько фильтров, которые позволяют посмотреть отличия конфигураций. При слиянии веток Git выполняется трехстороннее сравнение: берется общий предок и изменения, сделанные относительно него в одной и в другой ветке. Если эти изменения не противоречат друг другу, то они объединяются автоматически. Если в одной и в другой ветке изменен, грубо говоря, один и тот же элемент приложения, то в этом случае возникает конфликт, который вы должны разрешить вручную. При слиянии веток 1C:EDT устанавливает в редакторе фильтр Показывать потенциальные проблемы, который, в том числе, показывает конфликты. Вы видите, что такой конфликт есть в модуле приложения.
  6. Чтобы увидеть, в чем заключается конфликт, нажмите шестеренку в строке Модуль приложения. 1C:EDT откроет редактор сравнения и объединения модулей;
    В левом поле находится текст модуля из вашего текущего каталога, то есть из ветки master. В правом поле — текст модуля из ветки feature, которую вы вливаете в master. В центре — результат объединения, который предлагает 1C:EDT.
    Чтобы понять, какие изменения были выполнены в модуле, на следующих картинках будет показан его исходный текст, то есть текст, который находится в коммите, являющемся общим родителем для обоих веток;
  7. Первая область, которую содержит модуль, это область объявления переменных.
    В ней каждый из разработчиков добавил объявление своей переменной. 1C:EDT не может самостоятельно решить, какую из этих строк нужно вставить в результат, поэтому помечает эту область как конфликт, красными скобками;
  8. Следующие три процедуры не содержат конфликтов.
    • Процедура ПередНачаломРаботыСистемы() изменена в ветке master и 1C:EDT предлагает поместить в результат этот вариант;
    • Процедура ПриГлобальномПоиске() изменена только в ветке feature и 1C:EDT в данном случае понимает это и берет в результат измененную процедуру;
    • Третья процедура, ПриНачалеРаботы(), не имеет изменений;
  9. А вот в конце модуля каждый из разработчиков добавил по собственной процедуре.
    Несмотря на то, что процедуры имеют разные имена, 1C:EDT, при обычном сравнении, воспринимает их просто как любой другой текст программы, и, как и в начале модуля, помечает эту область как конфликт, красными скобками;
  10. Таким образом в модуле есть два конфликта, которые требуют вашего решения. Однако это не значит, что 1C:EDT совсем не знает, как поступить с конфликтами. 1C:EDT имеет две стратегии объединения конфликтных изменений и стандартной является стратегия объединения с приоритетом главного источника. Когда вы вливаете ветку feature в ветку master, то главный источник — это master. И значит в тех местах, где есть конфликты, 1C:EDT предлагает взять в результат изменения, выполненные в ветке master, то есть из левого поля;
  11. Интереса ради можете посмотреть, как работает вторая стратегия разрешения конфликтов. Для этого переключите вариант объединения на Объединить с приоритетом второго источника. Второй источник — это feature, 1C:EDT будет брать в результат изменения из правого поля;
    Верните прежнюю стратегию объединения — Объединить с приоритетом главного источника;
  12. Хорошо, что 1C:EDT имеет стратегии разрешения конфликтов, но в данном случае нужно включить в результат изменения, выполненные обоими разработчиками: объявление переменных ГлавнаяПеременная и ВтораяПеременная, а также процедуры ГлавнаяПроцедура() и Вторая(). Это можно сделать только вручную, скопировав нужные строки и вставив их в центральное поле. Но сейчас вы это делать не будете, а попробуете второй способ сравнения;
  13. Закройте редактор сравнения и объединения модулей, закройте редактор сравнения и объединения конфигураций. В панели Навигатор снова нажмите Групповая разработка > Слить... в контекстном меню проекта. На этот раз так же выберите локальную ветку feature, а кроме этого установите флажок Сравнивать модули с учетом структуры. Нажмите Слить;
  14. Редактор сравнения и объединения конфигураций по-прежнему покажет вам конфликт в модуле приложения, но под ним будет еще одна строка, говорящая о том, что конфликт находится в разделе определения переменных. Других конфликтов нет, а вы помните, что раньше в модуле было два конфликта. Чтобы понять, что произошло, переключите фильтр на трехстороннее сравнение;
  15. Вы увидите, что 1C:EDT разделила весь модуль на отдельные процедуры и с каждой из них «разобралась» отдельно:
    • В разделе определения переменных конфликт, с этим ничего не поделать;
    • Процедура ПриГлобальномПоиске() изменена только в ветке feature, поэтому у нее установлен флажок объединения;
    • Процедура ПередНачаломРаботыСистемы() изменена только ветке master, поэтому у нее флажок объединения сброшен, будет взят тот вариант, который в ветке master;
    • Процедура ПриНачалеРаботы() не изменялась, она не участвует в объединении;
    • Процедура ГлавнаяПроцедура() добавлена только в ветке master, поэтому у нее флажок объединения сброшен, она будет взята из ветки master;
    • Процедура Вторая() добавлена только в ветке feature, поэтому у нее установлен флажок объединения, она будет взята из этой ветки;
  16. Чем хорошо сравнение модулей с учетом структуры:
    • 1C:EDT может более правильно оценить изменения в каждой из веток и слить их без конфликтов (пример — процедуры ГлавнаяПроцедура() и Вторая());
    • Вы можете использовать разные стратегии объединения (взять из главного источника или из второго источника) для отдельных процедур. Когда вы сравниваете без учета структуры, стратегию объединения можно выбрать только для всего модуля целиком;
    • В редакторе сравнения и объединения модулей каждую процедуру можно сравнивать в отдельности, это может быть более удобным, т.к. остальной текст модуля вас не отвлекает;
    Чем неудобно сравнение модулей с учетом структуры:
    • Требуется дополнительное время для того, чтобы 1C:EDT разобрала содержимое модуля и построила его структуру. Только после этого выполняется сравнение;
    • В результате некоторых проблем (синтаксические ошибки, некорректное использование инструкций препроцессора), 1C:EDT не всегда может разобрать содержимое модуля и тогда модуль будет сравниваться без учета структуры;

    По этим причинам флажок Сравнивать модули с учетом структуры стандартно сброшен;

  17. Чтобы разрешить конфликт в разделе определения переменных, нажмите на шестеренку в строке Модуль приложения. Откроется знакомый вам редактор сравнения и объединения модулей, но для каждой процедуры в нем будет отдельная строка. Выделите строку Раздел определения переменных.
    Как вы уже знаете, чтобы включить в результат изменения обоих разработчиков, нужно скопировать их в центральное поле вручную. Изменения, выполненные в ветке master, там уже есть.
    Скопируйте строку Перем ВтораяПеременная Экспорт; из правого поля в центральное. Нажмите ОК.
  18. В редакторе сравнения и объединения конфигураций вы увидите на шестеренке отметку о том, что режим сравнения в какой-то из процедур установлен вручную, а в строке Раздел определения переменных как раз и будет указан режим Ручное объединение. Нажмите Объединить;
  19. Объединение будет выполнено и вы увидите измененный текст модуля приложения. Он включает изменения обоих разработчиков. Как вы понимаете, в первом варианте сравнения, без учета структуры, вы могли бы точно так же перенести в результат оба определения переменных и обе процедуры в конце модуля;
  20. 1C:EDT автоматически создала коммит слияния и озаглавила его Merge branch 'feature'. Это хорошо, но по условиям примера вы должны указать в этом коммите, каким образом вы разрешили конфликты слияния. Это нужно для того, чтобы другие разработчики могли правильно понять историю изменений;
  21. Чтобы дополнить сообщение, исправьте последний коммит. До тех пор пока это ваш локальный коммит, пока вы его никуда не отправили, это можно делать безболезненно. В сообщение коммита допишите, отделив пустой строкой, «Объединить изменения обоих разработчиков»;
  22. В результате вместо последнего коммита будет создан другой, точно такой же, но содержащий ваше сообщение;