Подмодуль Git для общих модулей 1С: проверка на «Нано-УТ», платформа пропустила 28 вызовов
Разработка - Групповая разработка (Git, хранилище)
Файлы
ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.
Подписка PRO — скачивайте любые файлы со скидкой до 85% из Базы знаний
Оформите подписку на компанию для решения рабочих задач
Оформить подписку и скачать решение со скидкойВы можете заказать платную доработку или адаптацию этой разработки под вашу конфигурацию на «Бирже заказов».
- 0% комиссии — оплата напрямую исполнителю;
- Исполнители любого масштаба — от отдельных специалистов до команд под проект;
- Прямой обмен контактами между заказчиком и исполнителем;
- Безопасная сделка — при необходимости;
- Рейтинги, кейсы и прозрачная система откликов.
Подмодуль решает задачу хранения одной версии общих модулей в нескольких проектах, если библиотека занимает весь каталог CommonModules. Остальные случаи требуют копирования или расширения, и у каждого пути ограничения, названные ниже. В архиве скрипты опыта, диагностика состояния подмодулей, тесты и журналы.
- Платформа грузит рабочую копию и ничего не знает о коммитах и указателях Git.
- Свой общий модуль проекта в каталоге подмодуля становится неотслеживаемым файлом подмодуля.
- Модули расширения не видны основной конфигурации при компиляции.
- Совместимость версий библиотеки /CheckModules не проверяет.
состояние подмодулей надо проверять до загрузки в базу, потому что платформа о нём не сообщает.
Для кого: разработчики 1С, которые хранят выгрузку конфигурации в Git и решают, как делить общий код между проектами.
- Стенд
- Как устроена выгрузка и что из этого следует для подмодуля
- Эталон и клон с --recursive
- Клон без --recursive
- Правка внутри подмодуля: от файла до клона коллеги
- Переключение веток с разными версиями библиотеки
- Обновление версии библиотеки в одном проекте
- Что допускает загрузка: структура выгрузки
- Копирование вместо подмодуля
- Расширение вместо подмодуля
- Скрипт проверки состояния подмодулей
- Сколько занимают операции
- Практические правила по результатам опыта
- Что не проверено
- Файл к статье
- Итог
- Источники
Команда ведёт два проекта на одной базе кода, и общие модули надо держать в одном месте. Подмодуль Git для этого выглядит естественно, но выгрузка конфигурации 1С устроена иначе, чем обычный каталог с исходниками: пути в ней задаёт платформа. Я проверила на платформе 8.3.27, что остаётся рабочим, когда каталог общих модулей становится подмодулем, и какие ошибки Git молча доходят до базы.
Стенд
| Условие | Значение |
|---|---|
| Платформа | 1С:Предприятие 8.3.27.2130 x86, пакетный Конфигуратор, файловая база |
| Выгрузка | «Нано-УТ 2.0»: 81 BSL и 212 XML, 16 общих модулей в CommonModules |
| Инструменты | Git for Windows 2.56.0.windows.1 (core.autocrlf=true), Python 3.12.10, стандартная библиотека |
| Компьютер | Windows 11 Pro, Intel Core i5-2400, 7,9 ГБ ОЗУ, SATA SSD |
| Нагрузка | Параллельно работали посторонние процессы, в том числе другие сеансы 1cv8.exe; времена ниже нельзя считать характеристикой Git или платформы |
| Метод | Настоящие репозитории, подмодули по локальному пути, платформа после каждого шага; версия библиотеки в базе определена по хешам модулей после обратной выгрузки |
Один прогон каждого сценария, повторов и средних значений нет. Сеть, авторизация на сервере Git и большие репозитории не проверялись.
Как устроена выгрузка и что из этого следует для подмодуля
Выгрузка конфигурации в XML имеет фиксированные пути. Configuration.xml перечисляет общие модули в ChildObjects, а для каждого модуля платформа ищет два объекта: файл CommonModules/Имя.xml и каталог CommonModules/Имя/Ext/Module.bsl. Файл описания лежит рядом с каталогом модуля, вне его.
Из этого следует, что подмодуль можно смонтировать в src/CommonModules целиком: тогда файл описания и каталог каждого модуля библиотеки оказываются на нужных местах. Схема «один подмодуль на один модуль» по этой структуре не складывается: описание Имя.xml остаётся за пределами каталога Имя/, и в подмодуль на уровне каталога модуля оно не попадёт. Эту схему я отдельно не проверяла. Подмодуль на уровень глубже, лишний модуль и свой модуль в каталоге библиотеки я прогнала на платформе (раздел про структуру ниже).
Опыт построен так. Репозиторий nano-lib содержит каталог CommonModules «Нано-УТ» (16 модулей) в корне. Два проекта, retail и wholesale, содержат остальную выгрузку и подключают nano-lib подмодулем в src/CommonModules с веткой main в .gitmodules. Проекты отличаются только именем конфигурации в Configuration.xml (НаноУТ и НаноОпт): других различий в коде у них нет, поэтому опыт не показывает, как подмодуль ведёт себя при реальных расхождениях проектов.
Версии библиотеки: v1 (исходные модули), v2 (комментарий в начале модуля ЦеныУчет), v3 (в модуле УчетСервер экспортная процедура Пересчитать переименована в ПересчитатьУчет, в документах и формах проекта 28 вызовов УчетСервер.Пересчитать).
Что именно загрузила платформа, видно только по содержимому базы. Поэтому после каждой загрузки скрипт делает обратную выгрузку /DumpConfigToFiles, считает хеш каждого Module.bsl и сопоставляет набор хешей с известной версией библиотеки. Хеши считаются после приведения переводов строк к LF и снятия BOM. В первом прогоне я этого не делала и увидела совпадение с диском для 13-14 модулей из 16: Git с autocrlf=true кладёт в рабочую копию CRLF, а выгрузка платформы использует LF. Прогон я прервала, исправила сравнение и повторила; журнал прерванного прогона приложен отдельно.
Эталон и клон с --recursive
Выгрузка без подмодулей загрузилась командой /LoadConfigFromFiles за 41,7 с, /CheckModules отработала за 23,5 с, оба кода возврата равны 0.
Клон проекта retail с --recursive занял 20,2 с. Платформа загрузила его без замечаний: код 0 и у загрузки, и у проверки, а обратная выгрузка по хешам совпала с версией v1 для всех 16 модулей. Файл .git, который подмодуль кладёт в каталог src/CommonModules, платформе не мешает.
Клон без --recursive
Обычный git clone проекта занял 2,5 с, и каталог src/CommonModules после него пуст. Команда git submodule status показывает перед хешем минус: подмодуль не инициализирован.
Платформа на таком клоне остановилась на загрузке с кодом 1. В журнале 32 строки вида «Файл объекта не существует» с путём к файлу ПродажиСервер.xml и остальным модулям: по одному сообщению на каждый из 16 модулей, и каждое сообщение повторено дважды. Начало текста сообщений указывает на путь в src/CommonModules, но не говорит, что причина в Git.
Команда git submodule update --init заняла 11,0 с, после неё загрузка и проверка прошли, версия в базе v1. Этот сбой заметен сразу: база не собирается. Остальные сценарии опаснее тем, что платформа молчит.
Правка внутри подмодуля: от файла до клона коллеги
В клоне retail я добавила строку комментария в модуль ЦеныУчет внутри src/CommonModules и прошла по шагам, фиксируя состояние Git, ответ скрипта проверки и содержимое базы.
| Шаг | Что показал Git в проекте | check_submodules.py | Что загрузила платформа |
|---|---|---|---|
| 1. Правка в файле, коммитов нет | git status --short: «m src/CommonModules»; git commit -m без добавления: код 1, «no changes added to commit» | DIRTY | Загрузка и проверка прошли, в базе версия не из коммитов библиотеки (отредактированный файл) |
| 2. Коммит внутри подмодуля, указатель в проекте не записан | «M src/CommonModules» | POINTER_DIFF:AHEAD и UNPUSHED | У коллеги, склонировавшего проект в этот момент, в базе версия v1 |
| 3. Указатель записан и отправлен, библиотека не отправлена | git push проекта прошёл (код 0) | UNPUSHED | Клон коллеги с --recursive упал с кодом 128 |
| 4. Библиотека отправлена, у коллеги выполнен git submodule update --init | Замечаний нет | замечаний нет | В базе версия v2 |
Шаг 1 показывает главное свойство платформы: она загружает рабочую копию без оглядки на коммиты. Правка, которой нет ни в одном коммите, попала в базу, и проверка модулей её приняла.
На шаге 2 разработчик видит рабочую базу с правкой, а коллега получает v1. Git при этом не сообщает ничего тревожного: изменение указателя видно только в git status как «M src/CommonModules», и его легко пропустить в списке файлов.
На шаге 3 проект с указателем на несуществующий для сервера коммит успешно отправлен. Клон у коллеги остановился с сообщениями «not our ref» и «Fetched in submodule path, but it did not contain» с хешем коммита. Результат клона остался в промежуточном состоянии: скрипт проверки показал POINTER_DIFF:OTHER (записан один коммит, выбран другой) и DIRTY на 32 файла в подмодуле. Такой клон нельзя использовать, пока библиотека не отправлена и подмодуль не обновлён.
Переключение веток с разными версиями библиотеки
В проекте retail на ветке main указатель стоит на v2, а на ветке old-lib, созданной от предыдущего коммита, на v1.
| Действие | Выбранная версия подмодуля | Что загрузила платформа | check_submodules.py |
|---|---|---|---|
| git checkout old-lib (submodule.recurse не задан), 0,7 с | v2 (осталась) | v2 при записи v1 на ветке | POINTER_DIFF:AHEAD и LAGGING |
| git submodule update, 25,6 с | v1 | v1 | LAGGING (библиотека ушла вперёд) |
| git config submodule.recurse true, затем git checkout main, 30,1 с | v2 | v2 | замечаний нет |
| git checkout old-lib при submodule.recurse=true, 31,9 с | v1 | не загружалась | LAGGING |
Первая строка таблицы важна: после обычного переключения ветки Git оставил подмодуль на v2, платформа загрузила v2, хотя ветка записывает v1, и сборка прошла без ошибок. С параметром submodule.recurse=true переключение само перемещает подмодуль, но занимает на стенде около 30 с вместо долей секунды. Что перемещение занимает именно столько и при других условиях, я не проверяла.
Обновление версии библиотеки в одном проекте
Библиотека получила v3 с переименованной процедурой. До обновления скрипт с ключом --fetch показал для обоих проектов LAGGING: wholesale отстал на 2 коммита, retail на 1.
Обновление retail командой git submodule update --remote заняло 65,5 с. Платформа загрузила v3, код возврата и загрузки, и /CheckModules равен 0. Это важный результат: в проекте остались 28 вызовов УчетСервер.Пересчитать, процедуры с таким именем в v3 уже нет, а проверка модулей на стенде ничего не сообщила. Тот же эффект наблюдался в опыте с хуком pre-commit на этой же выгрузке: вызов несуществующей процедуры общего модуля из другого модуля не останавливает /CheckModules. Выполнение этих вызовов в режиме предприятия я не запускала.
Проект wholesale при этом остался на v1: записан и выбран один и тот же коммит, платформа загрузила v1, скрипт показал LAGGING на 2 коммита. Подмодуль закрепляет версию на проект, а обновлять её приходится по проектам вручную. Это и есть смысл подмодуля, но он требует, чтобы кто-то заметил отставание. Для этого и нужна проверка из архива.
Что допускает загрузка: структура выгрузки
Все предположения проверены на отдельных копиях выгрузки.
| Опыт | Результат загрузки | Что видно в Git |
|---|---|---|
| Библиотека лежит на уровень глубже: src/CommonModules/Библиотека/ | Код 1, те же сообщения «Файл объекта не существует» по 16 модулям | |
| В каталоге лежит лишний модуль, которого нет в Configuration.xml | Код 0, на диске 17 модулей, в базе 16, лишний модуль в базу не попал | |
| Свой модуль проекта (ОптовыеЦены) положен в каталог подмодуля и добавлен в Configuration.xml | Код 0, на диске и в базе 17 модулей | Подмодуль грязный: «?? ОптовыеЦены.xml; ?? ОптовыеЦены/»; в git status проекта «? src/CommonModules» |
Платформа допускает свой модуль рядом с библиотекой, но для Git этот модуль чужой в каталоге подмодуля. Его не получится закоммитить в проект: неотслеживаемые файлы лежат внутри подмодуля. Придётся либо отправлять их в общую библиотеку, либо отказаться от своих общих модулей в каталоге CommonModules. Это главное ограничение: при монтировании на весь каталог у проекта не остаётся места для собственных общих модулей.
Ещё одно следствие. Лишний модуль в каталоге, не указанный в Configuration.xml, не загружается и не вызывает ошибки. Поэтому библиотека может содержать больше модулей, чем нужно проекту, и проект выберет нужные в Configuration.xml. Подход рабочий для загрузки, но Configuration.xml при этом остаётся в проекте, и каждое добавление модуля в библиотеку нужно отдельно подключать в каждом проекте.
Копирование вместо подмодуля
Если проекту нужны собственные общие модули, остаётся копирование. Скрипт sync_lib.py копирует Имя.xml и каталог Имя/ каждого модуля библиотеки в src/CommonModules и ничего не делает с чужими модулями. На стенде скрипт скопировал 32 объекта (16 файлов описания и 16 каталогов). Свой модуль ОптовыеЦены, добавленный в проект рядом, загрузился вместе с библиотекой: на диске и в базе по 17 модулей.
Копии отслеживает уже сам проект, поэтому главный вопрос: заметит ли кто-нибудь правку в копии. Режим sync_lib.py --check до правки не нашёл расхождений, после добавления строки в копию ЦеныУчет назвал этот модуль. Обновление копий остаётся ручным действием, а история библиотеки существует только в её репозитории.
Расширение вместо подмодуля
Другой путь: вынести общие модули в расширение конфигурации. Для проверки я написала выгрузку расширения с двумя собственными общими модулями и префиксом имён «Рс_» и загрузила её командой /LoadConfigFromFiles с ключом -Extension. Загрузка прошла с кодом 0, /CheckModules с ключом -Extension тоже (код 0).
Затем я проверила видимость модуля расширения. Вызов модуля основной конфигурации из модуля расширения (Рс_Вызов обращается к ЦеныСервер.ЦенаНаДату) прошёл проверку. Обратный вызов, из модуля ПродажиСервер основной конфигурации к модулю Рс_Цены, остановил /CheckModules с кодом 101 и сообщением «Переменная не определена (Рс_Цены)» в строке 10, колонке 13. Основная конфигурация не видит общих модулей расширения при компиляции.
Значит, расширение подходит для общего кода, который вызывается из других расширений или из собственного кода расширения, но не для библиотеки, которую должна вызывать основная конфигурация. Как расширение ведёт себя при обновлении платформы, в клиент-серверной базе и в режиме предприятия, я не проверяла. Выгрузку расширения я собирала вручную по структуре основной конфигурации, это не выгрузка из готового расширения.
Скрипт проверки состояния подмодулей
Скрипт check_submodules.py читает индекс проекта и для каждого подмодуля называет состояния, которые встретились в сценариях выше.
| Код | Что означает | Где встретилось |
|---|---|---|
| NOT_INIT | Каталог подмодуля не инициализирован | Клон без --recursive |
| POINTER_DIFF:AHEAD | Выбранный коммит новее записанного | Забытая запись указателя, переключение ветки |
| POINTER_DIFF:BEHIND | Выбранный коммит старше записанного | Только в тестах, в сценариях платформы не возникало |
| POINTER_DIFF:OTHER | Коммиты находятся на разных ветках | Неудачный клон из-за неотправленной библиотеки |
| DIRTY | В подмодуле есть изменённые или неотслеживаемые файлы | Правка до коммита, свой модуль в каталоге |
| UNPUSHED | Выбранный коммит не найден в удалённых ветках | Коммит библиотеки не отправлен |
| LAGGING | Записанный указатель отстал от ветки библиотеки | Обновление версии |
Запуск: python -X utf8 subs/check_submodules.py путь/к/проекту [--fetch] [--json]. Код возврата 0 при чистом состоянии, 1 при замечаниях, 2 если путь не репозиторий. Скрипт ничего не меняет, кроме git fetch в подмодулях при ключе --fetch.
Скрипт сравнивает коммиты и не читает содержимое модулей. Совместимость версий библиотеки с вызывающим кодом он не проверяет, как показал сценарий v3.
Сколько занимают операции
| Операция | Время, с |
|---|---|
| git clone --recursive проекта | 20,2 |
| git clone без --recursive | 2,5 |
| git submodule update --init | 11,0 |
| git submodule add (два проекта) | 10,3 и 5,5 |
| git checkout с submodule.recurse=true | 30,1 и 31,9 |
| git submodule update --remote | 65,5 |
| /LoadConfigFromFiles без подмодулей (эталон) | 41,7 |
| /LoadConfigFromFiles в разных сценариях, 14 успешных загрузок | от 15,8 до 61,1 |
Одна и та же выгрузка загружалась от 15,8 до 61,1 с. Столько вносит нагрузка от других процессов на машине, поэтому разницу между сценариями по времени платформы я не интерпретирую. Времена Git тоже отдельные измерения на загруженной машине.
Практические правила по результатам опыта
- Подмодуль подходит, если библиотека занимает весь src/CommonModules и у проекта нет собственных общих модулей. В остальных случаях копирование с проверкой расхождений в опыте оставило меньше состояний, за которыми надо следить: грязных подмодулей в нём нет.
- Клонируйте с --recursive или выполняйте git submodule update --init сразу после клона. Сообщение платформы не называет причину.
- Коммитьте в подмодуле, отправляйте библиотеку и только затем отправляйте проект с новым указателем. В обратном порядке коллеги получают клон с ошибкой.
- Включите submodule.recurse=true или запускайте git submodule update после каждого переключения ветки. Иначе платформа получит версию библиотеки от предыдущей ветки.
- Запускайте проверку состояния перед загрузкой в базу в сборочном шаге. Платформа сама эту ошибку не покажет.
- Совместимость версий библиотеки с вызывающим кодом нужна отдельная проверка: /CheckModules на стенде её не дал.
Что не проверено
Одна платформа (8.3.27.2130 x86), одна конфигурация, файловая база. Клиент-серверный вариант, EDT, графические клиенты Git, Linux и macOS не проверялись. Подмодули были по локальному пути; удалённый сервер Git, авторизация и сеть не проверялись. Вложенные подмодули (подмодуль внутри подмодуля), символические ссылки и точки соединения Windows не проверялись. Оба проекта различаются только именем конфигурации. Исполнение вызовов в режиме предприятия не запускалось. Обновление платформы и поведение расширения в рабочей базе не проверялись.
Файл к статье
В архиве submodules-22-1-companion.zip находятся:
- subs/check_submodules.py: проверка состояния подмодулей проекта;
- subs/sync_lib.py: копирование модулей библиотеки и проверка расхождений;
- subs/onec.py: запуск платформы: база, загрузка, проверка, обратная выгрузка, хеши модулей;
- subs/run_scenarios.py: сценарии этой статьи с платформой (нужна выгрузка «Нано-УТ 2.0», в архив она не входит);
- subs/ext_experiment.py: опыт с расширением;
- tests: тесты без платформы на настоящих репозиториях Git;
- evidence: журналы прогонов за 24.10.2026, вывод тестов лежит там же;
- README.md: запуск и пределы.
Для проверки из чистой распаковки:
Тесты не требуют платформы и удаляют свои временные каталоги. На загруженной машине они идут несколько минут: каждый тест создаёт репозитории и подмодуль. Для повторения опыта с платформой передайте run_scenarios.py путь --src к выгрузке «Нано-УТ 2.0», новый каталог --work и путь журнала --out. Существующий --work скрипт не удаляет и завершается с ошибкой.
Итог
Подмодуль Git и выгрузка конфигурации 1С совместимы при одном условии: библиотека занимает весь каталог CommonModules. Платформа грузит то, что лежит на диске, и не знает про указатели Git, поэтому клон без --recursive даёт явную ошибку, а забытый указатель, неотправленная библиотека и смена ветки без обновления подмодуля дают базу не той версии без единого сообщения платформы. Скрипт из архива ловит такие состояния, но не ловит несовместимость версий: переименованная процедура прошла /CheckModules при 28 вызовах. Для проектов со своими общими модулями проще копирование с проверкой расхождений, а расширение не видно основной конфигурации.
Источники
Вступайте в нашу телеграмм-группу Инфостарт
См. также
02.11.2026 423 vanya_gonchar 2