Основные принципы
1. Конфигурация поставщика ведется в отдельной ветке (vanilla).
2. Процесс обновления на новый релиз поставщика сводится к тому, чтобы загрузить новый релиз в ветку vanilla, затем слить vanilla в основную ветку разработки (develop, master).
3. Слияние ветки vanilla в основную ветку выполняется через трехстороннее сравнение: vanilla, основная ветка, их общий предок.
Подготовка
Для демонстрации подготовим пример с проектом на ЗУП КОРП. Проект создадим с нуля.
Последовательность шагов
1. В промежуточную базу загружаем .dt из поставки типового релиза. Снимаем конфигурацию с поддержки.
2. Создаем рабочую область EDT. Добавляем проект конфигурации импортом конфигурации из промежуточной базы.
3. Настраиваем групповую разработку из EDT: создаем репозиторий, делаем первый коммит.
4. Выполняем оптимизацию формата хранения файлов проекта.
5. Создаем новую ветку: vanilla.
Промежуточный итог. Ветки master и vanilla на одном коммите и соответствуют типовой конфигурации, наших доработок в проекте еще нет. История репозитория на данном этапе:

6. Внесем в master несколько доработок. Добавим:
- новые объекты (справочник, регистр сведений и пр.)
- новое значение в типовое перечисление
- новые типы в определяемые типы
- новые методы в типовой общий модуль
- свой код в типовые методы общего модуля
В дальнейшем посмотрим, как эти изменения отразятся на процессе обновления на новый релиз поставщика.
Итог. Ветки master и vanilla разошлись. В ветке master теперь типовая конфигурация с нашими доработками, в vanilla - и сейчас и в дальнейшем - только типовая конфигурация. История репозитория:

Далее выполним первое обновление на новый релиз поставщика.
Обновление на новый релиз поставщика
Последовательность шагов
1. Подготовка промежуточной информационной базы.
1.1. Откройте информационную базу в режиме конфигуратора.
1.2. Загрузите информационную базу из файла .dt, входящего в поставку загружаемого релиза поставщика.
1.3. Снимите конфигурацию с поддержки.
2. Подготовка рабочей области EDT для работы с vanilla.
2.1. Создайте отдельную рабочую область для работы с vanilla (если не сделали этого ранее).
2.2. Откройте рабочую область.
2.3. Убедитесь, что репозиторий на ветке vanilla.
2.4. Запомните имя проекта и его версию платформы.
2.5. Удалите проект с очисткой содержимого на диске.
3. Импорт конфигурации нового релиза
3.1. Восстановите проект конфигурации в рабочей области импортом конфигурации из промежуточной базы, в которую ранее загрузили новый релиз. В форме настроек импорта повторите имя проекта и версию платформы.
4. Проект конфигурации и репозиторий.
4.1. Добавьте вновь созданный проект обратно в репозиторий.

Укажите тот репозиторий, из которого ранее удалили проект.
5. Работа с изменениями.
5.1. Отмените удаление файлов настроек проекта, расположенных в каталоге <имя_проекта>/.settings (если есть).
5.2. Выполните оптимизацию формата хранения файлов проекта.
5.3. Зафиксируйте изменения. Отправьте коммит в удаленный репозиторий. На этом работа с веткой vanilla завершена.

Изменения в рабочем каталоге репозитория после импорта из промежуточной базы конфигурации нового релиза.

Изменения в рабочем каталоге репозитория после оптимизации формата хранения.
6. Загрузка обновления в master.
6.1. Откройте рабочую область EDT.
6.2. Убедитесь, что репозиторий на ветке master.
6.3. Актуализируйте состояние отслеживаемых удаленных веток (Получить из origin).
6.4. Запустите слияние с удаленной веткой vanilla.

Настройки слияния с vanilla.
7. Работа в редакторе сравнения/объединения.
7.1. Отметьте к слиянию объекты, ошибочно пропущенные механизмом слияния.
7.2. Разрешите конфликты слияния (если есть).
7.3. Убедитесь, что механизм слияния не отметил к перезаписи нетиповые доработки.
7.4. Завершите слияние.
7.5. Отправьте в удаленный репозиторий созданный коммит слияния.

Редактор показывает, что не все изменения отчета будут слиты в master из vanillla (символ "-"). При этом доработок в данный отчет не вносились. Идентифицируем как неточность механизма слияния и вручную ставим "галочку" на корне отчета.

Механизм слияния корректно не отмечает к удалению нетиповые справочники.

Механизм слияния корректно не отмечает к удалению нетиповое значение перечисления.

Механизм слияния корректно оставляет в модуле нетиповые методы, а также не трогает доработки в типовом методе КадровыеДанныеСотрудников.

В типовой метод ПриОпределенииДоступныхДляПереводаМакетов ранее были внесены наши доработки, плюс изменения в методе есть и в новом релизе поставщика. Механизм слияния автоматически объединяет изменения: в результирующем методе есть и наши доработки и изменения релиза.

Механизм слияния корректно не отмечает к удалению добавленные типы из определяемых типов.

Механизм слияния корректно отмечает к добавлению новые элементы в состав плана обмена, при этом не удаляет из состава добавленный доработкой элемент.
8. Проверка слияния (рекомендуется).
8.1. Сравните состояние master и vanilla. Если слияние прошло успешно, в окне сравнения с фильтром трехстороннего сравнения будут только наши доработки.




Сравнение master с vanilla. В окне сравнения с фильтром трехстороннего сравнения только наши доработки.
Итог. В ветке vanilla актуальный релиз поставщика. В ветке master актуальный релиз поставщика с нашими доработками. Дальнейшие обновления на релизы поставщика выполняются по тому же сценарию.
История репозитория:

Дополнительно
1. В примере изменения вносятся в master напрямую. Это упрощение. На практике, как правило, используются feature-ветки, в т.ч. для слияния с vanilla. Плюс, ваше flow может содержать и другие ветки - например, develop.
2. В примере перед загрузкой в vanilla нового релиза проект предварительно очищается. Можно сказать, что мы полностью подменяем состояние проекта в vanilla новым состоянием. Но для загрузки нового релиза в vanilla можно пойти другим путем - импортировать изменения из конфигурации в текущее состояние проекта без его очистки. Тогда запустится процесс слияния конфигурации базы с проектом.
Я рекомендую использовать вариант, описанный в этой статье (с очисткой проекта). Практика показывает, что механизм слияния конфигурации базы с проектом нельзя назвать надежным - некоторые изменения из нового релиза могут "потеряться". Вариант с полной заменой состояния является более "чистым", а также хорошо ложится на автоматизацию через скрипт.
3. В примере новый релиз загружается в промежуточную базу из .dt. Это не обязательно. Если демо-данные в промежуточной базе не нужны, можно использовать загрузку конфигурации из .cf.
4. В примере выполняется оптимизация формата хранения файлов проекта. Это необязательно, но рекомендуется. Оптимизация в данном случае выполняет функцию нормализации файлов. Это имеет смысл, т.к. работа с проектом из EDT и работа через импорт конфигурации из базы всегда будут иметь разный результат на уровне файлов. Оптимизация же во многом приводит файлы проекта к одному "формату". Это позволяет убрать из коммитов фантомные изменения, вызванные импортом конфигурации из базы.
5. В некоторых больших проектах может потребоваться несколько итераций оптимизации формата хранения файлов. Проверить это просто: запустите оптимизацию формата хранения второй раз - если в Git снова есть изменения - это ваш случай. Вероятно, проблема на стороне EDT. Следует учитывать в работе.
Скрипт
Шаги с 1 по 5 могут быть автоматизированы. В качестве примера приведу скрипт на PowerShell.
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$WorkspaceDir = $null # Установить, если выполнять в определенной папке
$EdtCliPath = "C:\Program Files\1C\1CE\components\1c-edt-2025.1.4+15-x86_64\1cedtcli.exe" # Путь к 1cedtcli.exe
$TmpltsReleasesDir = "C:\Users\eakom\AppData\Roaming\1C\1cv8\tmplts\1c\hrmcorp" # Каталог шаблонов типовых релизов
$1cv8Dir = "C:\Program Files\1cv8\8.3.27.1719\bin" # Каталог версии платформы
$CleanWorkspaceDir = $false # Очищать рабочую область скрипта после выполнения. Полезно отключать для отладки
$RepoUrl = "git@gitlab.com:eakomarov/zup.git" # url удаленного репозитория, https или ssh.
$BranchName = "vanilla" # Имя ветки
$EdtProjectName = "zup" # Имя EDT-проекта конфигурации
function Invoke-OrExit {
param([scriptblock]$Command)
Write-Host "$Command" -ForegroundColor Cyan
& $Command
if ($LASTEXITCODE -ne 0) {
Write-Error "Команда завершена с кодом возврата: $LASTEXITCODE"
exit $LASTEXITCODE
}
}
function Clear-WorkspaceDirectory {
if ((Test-Path $WorkspaceDir) -and $CleanWorkspaceDir) {
Clear-Directory $WorkspaceDir
Write-Host "Рабочий каталог скрипта '$WorkspaceDir' очищен."
}
}
function Clear-Directory {
param([string]$Directory)
if (-not (Test-Path $Directory)) {
return
}
try {
Remove-Item -Path "$Directory\*" -Recurse -Force
}
catch {
# В версиях до PowerShell 6 могут быть проблемы с длинными путями файлов.
# Пробуем использовать командную строку для удаления.
$null = cmd /c "del /F /Q `"$Directory\*`" >nul 2>&1"
$null = cmd /c "for /d %i in (`"$Directory\*`") do @rmdir /S /Q `"%i`" >nul 2>&1"
}
}
trap {
Clear-WorkspaceDirectory
Write-Error "Скрипт завершен с ошибкой: $_"
exit 1
}
# Создание рабочего каталога скрипта.
if ([string]::IsNullOrEmpty($WorkspaceDir)) {
$uniqueId = [Guid]::NewGuid().ToString().Substring(0, 4)
$WorkspaceDir = Join-Path $env:TEMP "update-vanilla-branch-$uniqueId"
New-Item -ItemType Directory -Path $WorkspaceDir -Force | Out-Null
Write-Host "Создана временная папка: $WorkspaceDir"
}
# Очистка содержимое рабочего каталога.
Clear-Directory $WorkspaceDir
# Определение путей
$ibcmdPath = Join-Path $1cv8Dir "ibcmd.exe"
$configFilesDir = Join-Path $WorkspaceDir "config-files"
$repoDir = Join-Path $WorkspaceDir "repo"
$edtProjectDir = Join-Path $repoDir $EdtProjectName
# Определение путей для автономного сервера.
$standAloneDir = Join-Path $WorkspaceDir "stand-alone-server"
$standAloneConfigPath = Join-Path $standAloneDir "config.yml"
$standAloneDataDir = Join-Path $standAloneDir "ss-data"
$standAloneBaseDir = Join-Path $standAloneDir "base"
# Определение путей для 1cedtcli.
$edtWorkspaceDir = Join-Path $WorkspaceDir "edt-workspace-dir"
$edtCliTmpDir = Join-Path $WorkspaceDir "edtcli-tmp-dir"
# Определение списка папок релизов в каталоге шаблонов.
$versionFolders = Get-ChildItem -Path $TmpltsReleasesDir -Directory |
Where-Object { $_.Name -match '^\d+_\d+_\d+_\d+$' } | Sort-Object Name -Descending
if ($versionFolders.Count -eq 0) {
throw "Не найдены папки с версиями релизов в '$TmpltsReleasesDir'."
}
# Вывод списка доступных в tmplts версий релизов.
Write-Host "`nДоступные версии релизов:" -ForegroundColor Cyan
for ($i = 0; $i -lt $versionFolders.Count; $i++) {
Write-Host "$($i + 1). $($versionFolders[$i].Name)" -ForegroundColor Yellow
}
# Запрос номера версии.
do {
$choice = Read-Host "`nВыберите номер версии (1-$($versionFolders.Count))"
} while ($choice -notmatch "^\d+$" -or [int]$choice -lt 1 -or [int]$choice -gt $versionFolders.Count)
# Получение пути к файлу конфигурации релиза.
$selectedVersion = $versionFolders[[int]$choice - 1].Name
$tmpltsReleaseDir = Join-Path $TmpltsReleasesDir $selectedVersion
$configFilePath = Join-Path $tmpltsReleaseDir "1cv8.cf"
# Получение конфигурационных файлов из файла конфигурации.
Invoke-OrExit -Command { & $ibcmdPath server config init --database-path="$standAloneBaseDir" --out="$standAloneConfigPath" --schedule-jobs=false }
Invoke-OrExit -Command { & $ibcmdPath infobase create --config="$standAloneConfigPath" --data="$standAloneDataDir" --create-database --force }
Invoke-OrExit -Command { & $ibcmdPath config load $configFilePath --config="$standAloneConfigPath" --data="$standAloneDataDir" --force }
Invoke-OrExit -Command { & $ibcmdPath infobase config support disable --config="$standAloneConfigPath" --data="$standAloneDataDir" --force }
Invoke-OrExit -Command { & $ibcmdPath config export $configFilesDir --config="$standAloneConfigPath" --data="$standAloneDataDir" --force --ignore-unresolved-refs }
# Клонирование репозитория.
New-Item -ItemType Directory -Path $repoDir -Force | Out-Null
Invoke-OrExit -Command { & git clone -b $BranchName --single-branch --depth 1 $RepoUrl $repoDir }
Write-Host "Репозиторий склонирован."
# Установка настроек окончаний строк для Windows.
Invoke-OrExit -Command { & git -C $repoDir config --local core.autocrlf true }
Invoke-OrExit -Command { & git -C $repoDir config --local core.safecrlf false } # все текстовые файлы заливаем в репозиторий с окончанием строк LF без предупреждения.
# Импорт файлов конфигурации в проект рабочей области EDT.
Clear-Directory $edtProjectDir
#Remove-Item -Path "$edtProjectDir\*" -Recurse -Force
Invoke-OrExit -Command { & $EdtCliPath -data $edtWorkspaceDir -v -timeout 3600 -vmargs -Xmx8g -Djava.io.tmpdir=$edtCliTmpDir -DdisableProjectChecks=true -DdisableFTS=true -command import --configuration-files $configFilesDir --project $edtProjectDir }
Write-Host "Импорт файлов конфигурации в проект $EdtProjectName рабочей области EDT завершен."
# Подсчет количества изменений в рабочем каталоге репозитория.
$count = & git -C $repoDir status --short | Measure-Object -Line
Write-Host "Количество измененных и новых файлов репозитория после загрузки конфигурации поставщика: $($count.Lines)"
# Оптимизация формата хранения файлов проекта.
Invoke-OrExit -Command { & $EdtCliPath -data $edtWorkspaceDir -v -timeout 3600 -vmargs -Xmx8g -Djava.io.tmpdir=$edtCliTmpDir -DdisableProjectChecks=true -DdisableFTS=true -command clean-up-source --project-name $EdtProjectName }
Write-Host "Оптимизация формата хранения файлов проекта $EdtProjectName завершена."
# Подсчет количества изменений в рабочем каталоге репозитория.
$count = & git -C $repoDir status --short | Measure-Object -Line
Write-Host "Количество измененных и новых файлов репозитория после оптимизация формата хранения файлов: $($count.Lines)"
if ($count.Lines -eq 0) {
Write-Host "Нет изменений в рабочем каталоге репозитория. Скрипт прерван."
Clear-WorkspaceDirectory
exit 0
}
# Добавление изменений в индекс, кроме файлов-настроек из .settings
Invoke-OrExit -Command { & git -C $repoDir add --all -- ":!$EdtProjectName/.settings/*" }
Write-Host "Все изменения репозитория добавлены в индекс."
# Подсчет количества изменений в индексе репозитория.
$count = & git -C $repoDir diff --staged --name-only | Measure-Object -Line
Write-Host "Количество изменений в индексе репозитория: $($count.Lines)"
if ($count.Lines -eq 0) {
Write-Host "Нет изменений в индексе репозитория. Скрипт прерван."
Clear-WorkspaceDirectory
exit 0
}
# Коммит и пуш.
$formattedVersion = $selectedVersion.Replace("_", ".")
$commitMessage = "update to $formattedVersion"
Invoke-OrExit -Command { & git -C $repoDir commit -m "$commitMessage" }
Invoke-OrExit -Command { & git -C $repoDir push --quiet }
Clear-WorkspaceDirectory
Write-Host "Скрипт завершен."
Read-Host "Нажмите Enter для выхода."
По результату выполнения скрипта можно сразу перейти к слиянию vanilla в master (шаги с 6 по 8).
Если доработки в ваш проект вносятся строго в расширение или изменения в конфигурации минимальны и могут быть воспроизведены скриптом на уровне файлов, вы можете пойти дальше и автоматизировать весь процесс обновления.