Git для проекта ПЛК: Минимальный регламент для малой команды
2026-05-28 08:35
В малой команде хаос с версиями редко выглядит как большая управленческая проблема. Сначала все кажется терпимым: один инженер держит проект у себя на ноутбуке, второй просит «скинь последнюю версию», третий делает копию перед выездом на объект. На диске появляются папки final, final_new, object_after_sat, object_after_sat_fix, и какое-то время команда даже ориентируется в этом вручную.
Проблема вскрывается позже. Нужно понять, какая версия реально загружена в ПЛК. Нужно быстро откатиться после неудачной правки. Нужно доказать заказчику, что изменение перед пуском было проверено. Нужно сравнить проект до и после наладки. И внезапно выясняется, что самая важная версия лежит не в архиве, а «вроде бы у Сергея на рабочем столе».
Git в проектах ПЛК нужен не для того, чтобы сделать из небольшой инженерной группы IT-отдел. Он нужен для трех практичных вещей: знать, что сейчас является актуальной версией, понимать историю изменений и иметь управляемую точку отката. Без CI/CD, без сложных pipeline, без десятка обязательных статусов. Только минимальный регламент, который реально выдержит команда из 2-3 человек.
Подробно о том, зачем вообще версионировать PLC/SCADA-проекты как инженерные артефакты, мы уже писали в статье «Версионирование проектов ПЛК/SCADA как у кода: ветки, релизы, откат, ревью». Здесь фокус конкретнее: какой порядок принять внутри небольшой команды, чтобы Git не стал еще одной папкой для беспорядка.
Что именно класть в репозиторий
Первый спор обычно начинается с форматов. У ПЛК-проектов много бинарных файлов, архивов сред разработки, экспортов, библиотек, конфигураций панели и SCADA. Git лучше всего работает с текстом, но это не значит, что проекты автоматизации нельзя вести в Git.
В репозиторий стоит класть все, без чего нельзя восстановить рабочее состояние проекта:
•проект ПЛК в формате среды разработки или экспорт, если среда умеет давать читаемый текстовый вариант;
•проект панели, SCADA или локальной визуализации, если он относится к тому же объекту;
•конфигурации связи, таблицы тегов, карты сигналов, сетевые настройки, файлы импорта/экспорта;
•пользовательские библиотеки, функциональные блоки, шаблоны экранов, скрипты и отчеты;
•краткую документацию проекта: состав оборудования, порядок сборки, порядок загрузки, список релизов;
•файл с правилами команды: кто мержит, как называются ветки, как ставятся теги.
Если часть артефактов очень крупная или бинарная, можно использовать Git LFS либо хранить тяжелые архивы рядом в DMS/файловом хранилище, но в Git обязательно оставить ссылку на точный файл, контрольную сумму или номер пакета. Иначе репозиторий будет выглядеть аккуратно, но не сможет ответить на главный вопрос: из чего собран релиз.
Минимальная структура веток
Для малой команды не нужна сложная модель с десятками веток. Чем больше правил, тем выше шанс, что на объекте их обойдут. Рабочий минимум выглядит так:
Ветка
Для чего нужна
Кто может менять
main
Только версии, соответствующие выпущенным или загруженным релизам
Через merge после проверки
develop
Подготовка следующего рабочего состояния проекта
Инженеры после ревью или по правилам команды
feature/...
Отдельная доработка: новый экран, блок, драйвер, участок логики
Автор изменения
hotfix/...
Срочная правка от релизной версии, если объект уже работает
Ответственный инженер с обязательным возвратом в develop
Можно жить и без develop, если команда совсем маленькая и изменения редкие. Тогда main остается релизной веткой, а вся работа идет в коротких feature/... и hotfix/.... Но прямые правки в main лучше запретить сразу. Не из любви к формальностям, а потому что main должен отвечать на вопрос «что мы считаем выпущенным».
Название ветки должно помогать через месяц. feature/new_logic почти ничего не говорит. Лучше feature/pump-station-start-permissives, feature/hmi-alarm-screen, hotfix/di-filter-pump-2. Если есть заявка, MOC или номер задачи, его удобно добавить в имя или описание merge request.
Релизные теги: дата в имени файла не заменяет версию
Одна из самых вредных привычек в автоматизации - считать версией дату в названии архива. Дата полезна, но она не фиксирует точный состав изменений. Два инженера могут собрать два разных архива в один день. Один файл могут пересохранить через неделю, не меняя имени. А на объекте может оказаться промежуточная версия, которая никогда не называлась «финальной».
В Git релиз удобно фиксировать тегом:
v1.0.0-fat
v1.1.0-sat
v1.1.1-hotfix-pump2
v2.0.0-as-loaded
Формат можно выбрать свой, но он должен быть стабильным. В промышленном проекте особенно полезны суффиксы по смыслу:
•fat - версия, предъявленная на заводских испытаниях;
•sat - версия, предъявленная на объекте;
•as-loaded - версия, фактически загруженная в ПЛК или панель;
•hotfix - срочное исправление на работающем объекте;
•as-built - версия после приемки и фиксации фактического состояния.
Хороший релизный тег сопровождается коротким описанием: что изменилось, на каком оборудовании проверено, какие файлы входят в пакет, где лежит резервная копия загруженного проекта. Тогда тег становится не украшением истории, а точкой, от которой можно уверенно восстановиться.
.gitignore: что не должно засорять историю
В репозитории проекта ПЛК часто появляется мусор, который не несет инженерного смысла: временные файлы среды, локальные кэши, результаты сборки, пользовательские настройки рабочего места, автосохранения и резервные копии «на всякий случай». Если их коммитить, история быстро превращается в шум: в каждом изменении вроде бы тронуто 200 файлов, хотя инженер поменял один блок.
.gitignore нужен не для красоты, а для того, чтобы в коммит попадали только управляемые артефакты. Универсального списка для всех сред нет, но логика такая:
Для CODESYS, MasterSCADA и других сред правило простое: сначала создать тестовый репозиторий, открыть проект, собрать/сохранить его и посмотреть, какие файлы меняются без осмысленной правки. Все локальные и автоматически генерируемые файлы отправить в .gitignore, а все необходимые для восстановления проекта оставить под контролем версий.
Нельзя бездумно игнорировать все бинарные файлы. Некоторые бинарники и есть проект. Если среда хранит основную конфигурацию в своем контейнере, его нужно версионировать, просто понимать, что дифф будет ограниченным. В таком случае особенно важны экспортные текстовые отчеты, changelog и описание релиза.
Кто мержит: один владелец релиза лучше коллективной неопределенности
В маленькой команде часто думают: «нас всего трое, договоримся». Но именно в такой команде границы ролей размываются быстрее всего. Один инженер дописал блок, второй на объекте поправил уставку, третий пересобрал панель, и никто не уверен, кто должен объединить изменения.
Минимальный регламент должен назначить владельца релиза. Это не обязательно начальник. Это человек, который перед выпуском проверяет состав изменений, убеждается, что ветка актуальна, смотрит описание риска и ставит релизный тег.
Правило можно сформулировать жестко:
Автор изменения не мержит сам себе критичную правку в релизную ветку.
Для некритичных доработок это может быть легкое ревью: второй инженер смотрит, что не затронута аварийная логика, не изменены адреса без причины, не потеряны комментарии и документация. Для изменений в пусковых условиях, межблокировках, авариях, обмене с SCADA или алгоритме технологического цикла ревью обязательно.
Если команда работает одна на объекте и второго инженера физически нет, правило не отменяется. В таком случае в merge request или журнале релиза фиксируют самопроверку: что изменено, почему срочно, как проверено, как откатиться. Это хуже полноценного ревью, но лучше молчаливой правки в единственной копии проекта.
Коммит должен отвечать на вопрос «зачем»
Плохой комментарий к коммиту выглядит так:
Такие сообщения не помогают ни через неделю, ни после аварии. Хороший коммит короткий, но конкретный:
Для русскоязычной команды можно писать по-русски. Важно не язык, а смысл:
Добавлена блокировка сухого хода насоса 2
Исправлено подтверждение аварий на экране мешалки
Обновлена карта IO после ревизии шкафа B
Зафиксирован baseline перед SAT
Если изменение связано с риском, в описании коммита или merge request стоит указать проверку: «проверено на стенде», «проверено с симуляцией входа DI14», «загружено в ПЛК 2, резервная копия приложена». Это особенно полезно для legacy-проектов, где одна небольшая правка может затронуть старую логику. В статье «Технический долг в Legacy-ПЛК: когда рефакторить, а когда нет» мы отдельно разбирали, почему старый рабочий код нужно менять небольшими контролируемыми шагами.
Как откатываться без паники
Откат нельзя придумывать в момент, когда линия уже стоит. Для каждого релиза нужно заранее понимать три вещи:
1.Какой тег соответствует предыдущей рабочей версии.
2.Где лежит резервная копия фактически загруженного проекта.
3.Кто имеет право принять решение об откате на объекте.
Git сам по себе не откатывает ПЛК. Он дает точную версию проекта, к которой нужно вернуться. Дальше вступает в силу инженерная процедура: открыть нужный релиз, собрать проект, проверить совместимость с текущими библиотеками и устройством, загрузить в контроллер, зафиксировать факт отката.
Для малой команды достаточно простого файла RELEASES.md или раздела в паспорте проекта:
Версия: v1.1.0-sat
Дата: 2026-05-28
Состав: ПЛК, HMI, карта IO
Где проверено: стенд + SAT участок 2
Загружено: ПЛК-1, панель HMI-1
Откат: v1.0.0-fat, архив backup/v1.0.0-fat.zip
Ответственный: Иванов
Такая запись выглядит скучно, но именно она экономит часы при нештатной ситуации. Когда после пуска заказчику передают исходники, as-built и резервные копии, этот же подход хорошо ложится в паспорт объекта АСУ ТП после пуска: там должна быть не просто папка файлов, а понятная история версий.
Чек-лист: 7 правил Git для проекта ПЛК
Правило
Что сделать
Зачем
1. Один репозиторий на объект или систему
Хранить ПЛК, HMI/SCADA, карты IO и документацию в связанном контуре
Чтобы релиз был целым пакетом, а не набором случайных файлов
2. main - только для релизов
Запретить прямые правки в main, мержить туда после проверки
Чтобы всегда знать, что считается выпущенной версией
3. Любая работа - в отдельной ветке
Использовать feature/... и hotfix/... с понятными именами
Чтобы не смешивать разные изменения и проще ревьюить
Исключить кэши, временные файлы, логи и локальные настройки
Чтобы история не засорялась шумом
6. Мержит владелец релиза
Назначить ответственного за объединение и теги
Чтобы у релиза был конкретный хозяин
7. Откат описан до загрузки
Для каждого релиза указать предыдущую рабочую версию и место резервной копии
Чтобы восстановление было процедурой, а не поиском файлов
Если команда выполняет только эти семь правил, она уже уходит от режима «у кого последняя папка». Остальное можно наращивать позже: автоматические проверки, стендовые тесты, pipeline, шаблоны merge request. Но начинать лучше не с красивой DevOps-схемы, а с дисциплины, которую команда способна соблюдать каждый день.
Где Git заканчивается
Важно не переоценить инструмент. Git не заменяет FAT, SAT, MOC, журнал загрузок, резервное копирование и нормальную приемку. Он не скажет сам, безопасна ли правка в межблокировке. Он не гарантирует, что версия из репозитория действительно загружена в контроллер. Это должен подтвердить инженер.
Git дает основу: история, ветки, сравнение, теги, точка отката. Дальше вокруг нее строится инженерная процедура. Если проект уже вырос до автоматических сборок, тестов и staged rollout, можно переходить к промышленному CI/CD. Но для команды из 2-3 человек первый выигрыш почти всегда проще: убрать хаотичные архивы, договориться о ветках и перестать выпускать изменения без релизного тега.
Хороший признак, что регламент работает: любой инженер команды за несколько минут отвечает на три вопроса. Какая версия сейчас на объекте? Что изменилось с прошлого релиза? Как вернуться назад, если после загрузки обнаружится проблема?
Если ответы есть, Git уже приносит пользу. Если ответ звучит как «надо спросить, у кого файл», значит система версий пока существует только формально.