Skip to content

Latest commit

 

History

History
1129 lines (859 loc) · 88.9 KB

setup-guide.md

File metadata and controls

1129 lines (859 loc) · 88.9 KB

Установка и настройка: пошаговое руководство для администратора 1С

Это руководство рассчитано на администратора 1С, который не знает Python и не обязан его знать. Все команды даны для Windows PowerShell (тот, что открывается по «Пуск → Windows PowerShell»). Каждый шаг заканчивается блоком «Что должно получиться»: если видите не это — не идите дальше, а посмотрите раздел Если что-то не работает.

Примеры путей — условные (D:\gitsync\..., D:\git\base). Подставляйте свои. Примеры вывода взяты из настоящих прогонов, в них заменены только пути и имена.


1. Что именно вы настраиваете (прочитать до начала)

Есть два разных репозитория Git, и путать их нельзя:

Репозиторий программы Репозиторий выгрузки (ваш)
Что внутри исходный код gitsync-py (Python) XML-выгрузка хранилищ 1С: конфигурация и расширения
Кто владелец автор инструмента вы / ваша организация
Где создаётся вы его только скачиваете вы создаёте его сами, он приватный
Как называется в тексте ниже «репозиторий программы», D:\gitsync\program\gitsync-py «выходной репозиторий», D:\git\base

Что делает инструмент. Читает историю хранилища конфигурации 1С, по одной версии получает исходники через конфигуратор и делает по одному коммиту Git на каждую версию хранилища, сохраняя автора, дату и комментарий версии.

Чего инструмент не делает никогда (это ваша работа или работа ваших регламентов):

  • не отправляет ничего в удалённый репозиторий (git push вы делаете отдельно, см. шаг 12);
  • не пишет в хранилище 1С (не захватывает объекты, не помещает версии, не создаёт метки);
  • не правит и не перезаписывает историю Git, не делает force, reset, checkout;
  • не трогает файлы, которые не относятся к его подкаталогу выгрузки.

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

D:\git\base\                        <- один каталог .git на всю базу
├── README.md                       <- ваши файлы; инструмент их не трогает
├── Конфигурация\                   <- источник 1: хранилище основной конфигурации
│   ├── AUTHORS   VERSION
│   └── ...XML-выгрузка
├── Расширение печатных форм\       <- источник 2: хранилище расширения
│   ├── AUTHORS   VERSION
│   └── ...
└── Расширение обменов\             <- источник 3: другое хранилище расширения
    ├── AUTHORS   VERSION
    └── ...

Число расширений ничем не ограничено: сколько у вас хранилищ — столько записей в настройке. Ниже показаны основная конфигурация и два расширения, потому что так удобно объяснять; добавление третьего, четвёртого и следующих — это одна однотипная запись, см. раздел 14.

Четыре разных «логина», которые легко перепутать:

Кто Где задаётся Зачем
Авторы версий хранилища (кто работал в конфигураторе) приходят из отчёта хранилища, подписи настраиваются в файле AUTHORS становятся авторами коммитов Git
Пользователь хранилища, под которым читает инструмент storage_user + пароль ему достаточно права читать хранилище; инструмент в хранилище не пишет
Учётная запись Windows, под которой работает задача планировщик задач от неё зависят права на папки, сохранённые пароли Git и блокировки
Логин к серверу Git (GitLab/GitHub/Gitea…) Git Credential Manager, сохранённый в профиле той же учётной записи Windows нужен только для git push

2. Быстрый путь

Если хочется сначала общей картины: вот весь путь целиком. Каждая строка — ссылка на подробный шаг.

№ Что делаете Сколько занимает
1 Проверяете, что на машине есть Python, Git и 1С 10 мин
2 Создаёте четыре папки: программа, настройка, временные файлы, логи 2 мин
3 Устанавливаете программу в отдельное окружение Python 10 мин
4 Делаете репетицию на учебной фикстуре — без 1С и без хранилищ 5 мин
5 Готовите выходной репозиторий (пустой приватный + клон) 10 мин
6 Настраиваете пароль хранилища безопасным способом 10 мин
7 Пишете файл настройки (манифест) на все хранилища базы 20 мин
8 Первый запуск: init, правка AUTHORS, sync от 20 мин до нескольких часов
9 Проверяете результат в Git 10 мин
10 Отправляете в удалённый репозиторий 5 мин
11 Ставите регулярный запуск в планировщик задач 20 мин

3. Что должно быть на машине

Что Требование Как проверить
Windows Windows 10/11 или Windows Server с PowerShell 5.1 $PSVersionTable.PSVersion
Python 3.11 или новее (это требование самой программы) python -V или py -0p
Git для Windows 2.28 или новее (нужен git init -b) git --version
1С:Предприятие установленный толстый клиент с конфигуратором и действующая лицензия Get-ChildItem 'C:\Program Files\1cv8' -Directory покажет установленные версии; Test-Path '<путь>\bin\1cv8.exe' должен вернуть True
Хранилище 1С адрес хранилища и пользователь хранилища с правом чтения конфигуратором вручную: «Администрирование → Хранилище конфигурации»
Место на диске на диск временных файлов: не меньше, чем --jobs × (размер выгрузки конфигурации + файл .cf) см. шаг 13

Проверка одной командой (вывод должен содержать три версии, а не ошибки):

$PSVersionTable.PSVersion.ToString()
git --version
& "C:\Program Files\Python311\python.exe" -V

Что должно получиться

5.1.19041.6456
git version 2.55.0.windows.4
Python 3.11.3

Если Python не установлен — поставьте его с python.org (обычный установщик, галочка «Add python.exe to PATH» не обязательна: ниже везде используется полный путь). Если нет Git — поставьте Git for Windows, вместе с ним ставится Git Credential Manager, он понадобится на шаге 12.

Что проверено, а что нет

Честная картина (подробнее — docs/compatibility-matrix.md):

Конфигурация развёртывания Состояние
Windows 10 Pro + PowerShell 5.1 + Git 2.55 + Python 3.11 проверено
1С:Предприятие 8.3.27.2130, файловое хранилище конфигурации (каталог/UNC), синтетические данные проверено на стенде
Серверное хранилище (tcp://сервер/имя) проверено на настоящем crserver 8.3.27.2130: 17/17 версий, jobs=1/2, два именованных расширения; отчёт
Другие версии платформы 8.3 не проверялись
Несколько источников в одном репозитории (конфигурация + расширения) проверено
Одновременная работа двух задач по одному репозиторию последовательность обеспечивается блокировкой; работа из разных учётных записей Windows и с разных хостов не проверялась
Linux, Docker — образ ядра (Python + Git, без платформы 1С) проверено: сборка, все автотесты и пользовательские сценарии на фикстуре внутри контейнера, см. docs/docker-guide.md
Linux, Docker — работа с настоящим хранилищем 1С проверено на платформе 8.3.27.2130, файловый и TCP-доступ; нужны собственный дистрибутив и действующая лицензия; приёмка
Ветки кроме одной рабочей, submodules, sparse-checkout, worktrees не проверялись

Вывод для приёмки: начинайте с файлового хранилища или сначала проверьте серверное на копии. Первый прогон делайте на тестовом хранилище, а не на рабочем.


4. Раскладка папок

Четыре разных места, и их нельзя смешивать:

Что Пример пути Почему отдельно
Программа (исходники + окружение Python) D:\gitsync\program обновляется независимо, в Git выгрузки не попадает
Настройка и секреты D:\gitsync\config, D:\gitsync\secret должны лежать вне выходного репозитория, иначе пароль уедет в Git
Временные файлы (временные базы 1С, промежуточные выгрузки, протоколы конфигуратора) D:\gitsync\temp должны лежать вне выходного репозитория: инструмент отказывается работать, если временный каталог внутри рабочей копии
Выходной репозиторий D:\git\base здесь и только здесь работает Git
Логи запусков D:\gitsync\logs чтобы не росли внутри репозитория
New-Item -ItemType Directory -Path D:\gitsync\program, D:\gitsync\config, D:\gitsync\secret, D:\gitsync\temp, D:\gitsync\logs -Force
New-Item -ItemType Directory -Path D:\git -Force

Что должно получиться: шесть строк с именами созданных каталогов (или ничего не поменяется, если они уже есть).

Пути с кириллицей и пробелами работают (проверено). Но служебные пути (program, temp, logs) проще держать латиницей: меньше поводов для ошибок при копировании команд.


5. Установка программы

Ссылку на репозиторий программы вам даёт тот, кто её публикует. Пока репозиторий приватный, git clone спросит логин (это сделает Git Credential Manager); после публикации логин не нужен. Программа не публикуется в PyPI, поэтому pip install gitsync-py из интернета не сработает — ставим из папки с исходниками.

cd D:\gitsync\program
git clone https://github.com/<владелец>/gitsync-py.git

Создаём отдельное окружение Python и ставим программу в него. Активировать окружение не нужно и менять политику выполнения скриптов (Set-ExecutionPolicy) для этого тоже не нужно — мы всегда вызываем программу полным путём.

& "C:\Program Files\Python311\python.exe" -m venv D:\gitsync\program\venv
& "D:\gitsync\program\venv\Scripts\python.exe" -m pip install D:\gitsync\program\gitsync-py

Установка тянет из интернета только сборщик пакета (hatchling). Если на машине нет доступа к PyPI — соберите пакет на машине с доступом (python -m pip wheel --no-deps <папка с исходниками>), перенесите файл gitsync_py-*.whl и поставьте его: ... -m pip install <путь к .whl>.

Проверяем:

& "D:\gitsync\program\venv\Scripts\gitsync-py.exe" --version
& "D:\gitsync\program\venv\Scripts\gitsync-py.exe" --help

Что должно получиться

gitsync-py 0.1.0
usage: gitsync-py [-h] [--version] команда ...
...
    init       подготовить рабочую копию, создать AUTHORS и VERSION
    clone      git clone URL + подготовка AUTHORS/VERSION; затем sync
    sync       догрузить новые версии хранилища в git
    set-version
               записать номер синхронизированной версии в VERSION
    sync-all   пакетная синхронизация нескольких хранилищ из JSON-файла
    plugins    показать загруженные плагины Python

Подсказка по любой команде: gitsync-py sync --help, gitsync-py sync-all --help.

Если на машине задана переменная окружения PYTHONPATH (бывает, если кто-то ставил другие инструменты на Python), она «протекает» в окружение и может ломать запуск. Проверьте: Get-ChildItem Env:PYTHONPATH. Если переменная есть — гасите её в том же окне, только для текущего процесса и его дочерних: $env:PYTHONPATH = ''. Глобально ничего менять не нужно; готовый скрипт из шага 13 делает это сам.


6. Репетиция на учебной фикстуре

Прежде чем трогать 1С, убедитесь, что установка вообще работает. В репозитории программы есть учебная фикстура — каталог с заранее подготовленным «отчётом по версиям» и двумя «версиями». Это не 1С и не эмулятор 1С: это просто файлы, чтобы проверить Python, Git и права на запись.

$gitsync = "D:\gitsync\program\venv\Scripts\gitsync-py.exe"
$fixture = "D:\gitsync\program\gitsync-py\examples\fixture-storage"

& $gitsync init --workdir D:\gitsync\rehearsal --backend fixture --fixture-root $fixture --email-domain example.org
Get-Content D:\gitsync\rehearsal\AUTHORS -Encoding UTF8
& $gitsync sync --workdir D:\gitsync\rehearsal --backend fixture --fixture-root $fixture --jobs 2 --temp-root D:\gitsync\temp --email-domain example.org
& git -C D:\gitsync\rehearsal log --reverse --format='%h|%an|%ae|%ad|%s' --date=format:'%Y-%m-%d %H:%M:%S'

Что должно получиться

Рабочая копия подготовлена: D:\gitsync\rehearsal
Иванов=Иванов <Иванов@example.org>
Петров=Петров <Петров@example.org>
2026-09-16 07:34:33,071 INFO gitsync.sync: Синхронизированная версия: 0, максимум в хранилище: 2
2026-09-16 07:34:33,558 INFO gitsync.sync: Версия 1 зафиксирована (7f42d221...)
2026-09-16 07:34:34,029 INFO gitsync.sync: Версия 2 зафиксирована (e4cb2150...)
Зафиксировано версий: 2 (1..2)
7f42d22|Иванов|Иванов@example.org|2026-09-15 10:20:30|Первая версия конфигурации
e4cb215|Петров|Петров@example.org|2026-09-16 08:00:00|Доработка справочника Товары

Видно главное: автор, дата и комментарий каждой версии хранилища сохранились в коммите. Строки INFO ... — это обычный журнал работы, он идёт в «поток ошибок», это не ошибка.

Когда репетиция прошла — папку можно удалить: Remove-Item -Recurse -Force D:\gitsync\rehearsal.


7. Подготовка выходного репозитория

Порядок именно такой: сначала создать выходной репозиторий, потом запускать синхронизацию. Если запустить синхронизацию по подкаталогу, когда общего репозитория ещё нет, инструмент честно создаст репозиторий внутри подкаталога — и вместо одной истории базы получится несколько отдельных репозиториев.

7.1. Создайте на сервере Git пустой приватный репозиторий

Руками, в веб-интерфейсе вашего сервера (GitLab/GitHub/Gitea/Bitbucket):

  • видимость — приватный (в выгрузке лежит ваша конфигурация целиком);
  • без файлов инициализации (без README, без .gitignore) — репозиторий должен быть пустым;
  • запишите его адрес, например https://git.example.org/erp/base-sources.git.

7.2. Клонируйте его на машину синхронизации

git clone https://git.example.org/erp/base-sources.git D:\git\base

Для пустого репозитория Git честно предупредит warning: You appear to have cloned an empty repository. — так и должно быть.

7.3. Проверьте, как называется рабочая ветка

Не предполагайте main: у разных серверов и у разных настроек Git ветка по умолчанию разная (main или master). Спросите у самого репозитория:

git -C D:\git\base symbolic-ref --short HEAD

Что должно получиться: одна строка, например main. Это имя понадобится при отправке.

7.4. Две локальные настройки Git

Инструмент выставляет их сам, только если создаёт репозиторий с нуля. Ваш клон он не переделывает, поэтому задайте их один раз руками:

git -C D:\git\base config core.autocrlf false
git -C D:\git\base config core.quotepath false
git -C D:\git\base config --local --list | Select-String 'autocrlf|quotepath'
  • core.autocrlf false — чтобы ваши собственные операции Git (git add, git checkout) не переписывали переводы строк в выгрузке конфигуратора;
  • core.quotepath false — чтобы в git status и git log русские имена файлов были видны как Конфигурация/..., а не как \320\232....

Что должно получиться

core.autocrlf=false
core.quotepath=false

7.5. При желании положите свой README

Файлы в корне репозитория инструменту не мешают — он работает только внутри подкаталогов источников. Для своих коммитов Git попросит имя и почту; для коммитов выгрузки это не нужно (там автор берётся из версии хранилища):

git -C D:\git\base config user.name "Оператор синхронизации"
git -C D:\git\base config user.email "operator@example.org"
[System.IO.File]::WriteAllText('D:\git\base\README.md', "# Исходники базы: конфигурация и расширения`r`n", (New-Object System.Text.UTF8Encoding($false)))
git -C D:\git\base add README.md
git -C D:\git\base commit -m "описание репозитория"

8. Пароль хранилища и права доступа

Пароль нельзя передавать аргументом командной строки — программа это прямо запрещает, потому что аргументы видны всем процессам в системе. Есть два разрешённых способа:

Способ Для чего Ключ
Переменная окружения запуск руками из открытого окна PowerShell --storage-password-env ИМЯ / "storage_password_env"
Файл с паролем запуск по расписанию, когда спросить некого --storage-password-file ПУТЬ / "storage_password_file"

Если у пользователя хранилища пустой пароль — не указывайте ни того, ни другого.

8.1. Запуск руками: спросить пароль и не сохранять его

$secure = Read-Host 'Пароль пользователя хранилища' -AsSecureString
$env:GITSYNC_STORAGE_PASSWORD = [System.Net.NetworkCredential]::new('', $secure).Password

Переменная живёт только в этом окне PowerShell и в запущенных из него процессах; закрыли окно — её больше нет. В профиль пользователя она не пишется. Не используйте setx и не прописывайте пароль в переменные системы: это ровно то же, что оставить его в открытом виде навсегда.

Проверить, что переменная задана, не показывая значение:

(Test-Path Env:GITSYNC_STORAGE_PASSWORD) -and $env:GITSYNC_STORAGE_PASSWORD.Length -gt 0

Что должно получиться: True.

8.2. Запуск по расписанию: файл с паролем

У задачи планировщика нет человека, который введёт пароль, поэтому остаётся файл. Важно понимать честно: файл лежит в открытом виде. Защита — только права на файл. Поэтому:

  • файл вне выходного репозитория (иначе он попадёт в Git);
  • доступ — только учётной записи задачи и администраторам;
  • UTF-8 без BOM (см. раздел про кодировки): BOM станет частью пароля, и конфигуратор откажет в аутентификации;
  • пароль вводится вручную, не хранится в скриптах и не печатается в логах.
$secure = Read-Host 'Пароль пользователя хранилища' -AsSecureString
$plain = [System.Net.NetworkCredential]::new('', $secure).Password
[System.IO.File]::WriteAllText('D:\gitsync\secret\storage.pwd', $plain, (New-Object System.Text.UTF8Encoding($false)))
$plain = $null

# Права: убрать наследование, оставить чтение учётной записи задачи и полный доступ администраторам.
icacls D:\gitsync\secret\storage.pwd /inheritance:r `
    /grant:r ('*{0}:(R)' -f ([System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value)) `
    /grant:r '*S-1-5-32-544:(F)'
icacls D:\gitsync\secret\storage.pwd

Команда icacls с числовыми *S-1-... не зависит от языка Windows. Если задача будет работать под другой учётной записью — выдайте право чтения именно ей (/grant:r "ДОМЕН\учётка:(R)"), а не «всем».

Что должно получиться

обработанный файл: D:\gitsync\secret\storage.pwd
Успешно обработано 1 файлов; не удалось обработать 0 файлов
D:\gitsync\secret\storage.pwd BUILTIN\Администраторы:(F)
                              ДОМЕН\учётка:(R)

Пароль в логах и в тексте ошибок маскируется самой программой: в журнале вы увидите /ConfigurationRepositoryP ***, причём замаскирован и вывод самого конфигуратора (проверено).


9. Файл настройки (манифест)

Все хранилища базы описываются одним файлом JSON. Ниже — полный рабочий пример для основной конфигурации и двух расширений. Скопируйте его в D:\gitsync\config\base.json, замените значения на свои. Кодировка — UTF-8; BOM инструмент принимает, но привычнее сохранять без него (см. раздел про кодировки).

{
  "repository": "D:/git/base",
  "defaults": {
    "backend": "native",
    "init": true,
    "jobs": 2,
    "queue_limit": 2,
    "retries": 1,
    "email_domain": "example.org",
    "v8_path": "C:/Program Files/1cv8/8.3.27.2130/bin/1cv8.exe",
    "v8_version": "8.3.27.2130",
    "storage_user": "gitsync",
    "storage_password_file": "D:/gitsync/secret/storage.pwd",
    "temp_root": "D:/gitsync/temp",
    "lock_timeout": 1800,
    "designer_timeout": 3600
  },
  "storages": [
    {
      "name": "Конфигурация",
      "subtree": "Конфигурация",
      "storage_path": "D:/storages/base"
    },
    {
      "name": "Расширение печатных форм",
      "subtree": "Расширение печатных форм",
      "storage_path": "D:/storages/base-print",
      "extension": "РасширениеПечатныхФорм"
    },
    {
      "name": "Расширение обменов",
      "subtree": "Расширение обменов",
      "storage_path": "D:/storages/base-exchange",
      "extension": "РасширениеОбменов"
    }
  ]
}

Запуск — одной командой на всю базу:

& "D:\gitsync\program\venv\Scripts\gitsync-py.exe" sync-all --config D:\gitsync\config\base.json

9.1. Три уровня файла

  • repository — путь к общему выходному репозиторию. Если его ещё нет, он будет создан (git init -b main), но лучше создать заранее, как в шаге 7.
  • defaults — значения, общие для всех источников.
  • storages — список источников; значения в записи перекрывают defaults.

Пути в JSON пишите с прямыми слэшами (D:/gitsync/temp) — так не нужно думать об экранировании. Обратные слэши тоже допустимы, но их надо удваивать (D:\\gitsync\\temp).

9.2. Все ключи, которые понимает манифест

Верхний уровень: repository, defaults, storages. Любой другой ключ — ошибка, файл не будет выполнен (в том числе repositories из формата OneScript-версии: он не поддерживается).

Ключ записи хранилища Значение по умолчанию Что это
name путь рабочего каталога имя источника: печатается в журнале, по нему выбирают источник ключом --name. Должно быть уникальным
subtree — подкаталог источника внутри repository. Относительный путь, разделитель /. Это «витринное» имя папки, оно никак не связано с именем расширения в 1С
workdir — альтернатива subtree: отдельная рабочая копия по абсолютному пути. С subtree одновременно задавать нельзя
storage_path — адрес хранилища 1С: каталог (D:/storages/base, //server/share/base) или строка сервера (tcp://storage-server/base)
storage_user пусто пользователь хранилища, которому достаточно права чтения
storage_password_file — файл с паролем (UTF-8 без BOM)
storage_password_env — имя переменной окружения с паролем
extension пусто имя расширения в 1С — для хранилища расширения обязательно. Пусто для основной конфигурации
v8_path — полный путь к 1cv8.exe
v8_version пусто версия платформы (передаётся конфигуратору)
backend native native — настоящий конфигуратор; fixture — учебный каталог-фикстура (только для репетиций)
fixture_root — каталог фикстуры для backend: fixture
init нет выполнить подготовку (VERSION, AUTHORS) перед синхронизацией. Для первого запуска — true
no_authors false не создавать AUTHORS при подготовке
jobs 4 сколько версий выгружать одновременно. Каждая — отдельный сеанс конфигуратора и отдельная лицензия. Начинайте с 2
queue_limit 4 насколько конвейер может убежать вперёд сверх jobs
retries 1 повторы при временном сбое выгрузки. Ошибки конфигуратора (аутентификация, таймаут) не повторяются намеренно
temp_root каталог рядом с репозиторием корень временных файлов. Обязательно вне выходного репозитория
email_domain localhost домен для подписей авторов, у которых нет строки в AUTHORS
designer_timeout 3600 предел на один вызов конфигуратора, секунды
lock_timeout 30 сколько секунд ждать, если репозиторий занят другим запуском. Для регулярной задачи ставьте больше (1800)
limit — обработать не больше N версий за запуск (удобно для первой проверки)
allow_dirty false разрешить работу при незафиксированных изменениях в своём подкаталоге. По умолчанию запрещено — и это правильно
disable_auto_src false не искать подкаталог src внутри рабочего каталога
keep_temp false не удалять временные каталоги (только для разбора инцидента)
disable / disabled false временно выключить источник, не удаляя запись
plugins пусто список Python-модулей-плагинов (см. docs/plugins.md)

9.3. Имя расширения в 1С против имени папки

Это самая частая путаница. Значения независимы:

  • extension — имя расширения, как оно называется в 1С (свойство «Имя» объекта метаданных расширения, латиница/кириллица без пробелов, например РасширениеПечатныхФорм). Именно оно уходит конфигуратору как -Extension. Ошибётесь — конфигуратор вернёт ошибку, а не пустую выгрузку.
  • subtree — имя папки в вашем репозитории, любое удобное для чтения человеком, можно с пробелами: Расширение печатных форм.

Где посмотреть точное имя: конфигуратор → «Конфигурация → Расширения конфигурации» → колонка «Имя» (не «Синоним»!). Синоним — это то, что видит пользователь; для настройки нужно «Имя».

Для основной конфигурации ключ extension не указывают вообще.

9.4. Проверка манифеста без риска

Схема проверяется до любых действий, поэтому опечатку видно сразу:

& "D:\gitsync\program\venv\Scripts\gitsync-py.exe" sync-all --config D:\gitsync\config\base.json --name "нет такого источника"

Что должно получиться: сообщение Ошибка: В конфигурации нет хранилищ: нет такого источника и код возврата 2 — значит сам файл разобран и схема принята. Если вместо этого пришла жалоба на ключ — сначала исправьте её.


10. Первый запуск

10.1. Подготовка: VERSION и AUTHORS

init создаёт в каждом подкаталоге два служебных файла:

  • VERSION — номер последней выгруженной версии хранилища (<VERSION>0</VERSION> в начале);
  • AUTHORS — таблицу «пользователь хранилища → подпись в Git».

Для составления AUTHORS инструмент читает историю хранилища, поэтому на этом шаге уже нужны доступ к 1С и пароль. В манифесте за это отвечает "init": true, отдельной командой — так:

$gitsync = "D:\gitsync\program\venv\Scripts\gitsync-py.exe"
& $gitsync init --workdir "D:\git\base\Конфигурация" `
    --storage-path D:/storages/base --storage-user gitsync `
    --storage-password-file D:\gitsync\secret\storage.pwd `
    --v8-path "C:\Program Files\1cv8\8.3.27.2130\bin\1cv8.exe" --v8-version 8.3.27.2130 `
    --temp-root D:\gitsync\temp --email-domain example.org
Get-Content "D:\git\base\Конфигурация\AUTHORS" -Encoding UTF8

Что должно получиться

Рабочая копия подготовлена: D:\git\base\Конфигурация
Иванов=Иванов <Иванов@example.org>
Петрова=Петрова <Петрова@example.org>

10.2. Правка AUTHORS — до первой синхронизации

Это важный момент. Подписи берутся из AUTHORS в момент коммита, поэтому:

  • правка AUTHORS до первого sync — и вся история получит нормальные имена и почты;
  • правка после — подействует только на новые коммиты; ранее созданные останутся как были (переписывать историю инструмент не умеет и не будет).

Формат файла — строго Пользователь хранилища=Имя Фамилия <почта>:

// строки, начинающиеся с двух слэшей, — комментарии
Иванов=Иван Иванов <i.ivanov@example.org>
Петрова=Мария Петрова <m.petrova@example.org>

Правила, которые проверяет программа:

  • ровно один знак = в строке; строка с другим числом знаков = пропускается с предупреждением в журнале (Ошибка чтения файла авторов, строка <...>);
  • подпись должна иметь вид Имя <почта>. Если угловых скобок нет, вся строка станет именем, а почта окажется пустой;
  • пользователя, которого нет в AUTHORS, инструмент подпишет как Иванов <Иванов@домен>, где домен — это email_domain;
  • почта не приходит из 1С: в отчёте хранилища есть только имя пользователя. Любая почта в коммитах — либо из AUTHORS, либо собрана из имени и email_domain. Не выдавайте её за подлинный адрес сотрудника, если не заполнили AUTHORS сами.

Файл AUTHORS инструмент не коммитит — после синхронизации он останется в git status как неотслеживаемый (?? Конфигурация/AUTHORS). Это не мешает работе. Хотите видеть его в истории — зафиксируйте сами:

git -C D:\git\base add "Конфигурация/AUTHORS" "Расширение печатных форм/AUTHORS" "Расширение обменов/AUTHORS"
git -C D:\git\base commit -m "таблицы авторов источников"

10.3. Файл VERSION: не редактировать руками

VERSION — это отметка «до какой версии хранилища мы дошли». Инструмент опирается на неё, чтобы продолжить с места обрыва и не сделать дубли коммитов. Поэтому:

  • не правьте VERSION в блокноте «чтобы перезалить»: занижение номера повторит уже выгруженные версии, завышение — молча пропустит настоящие;

  • если номер действительно нужно изменить (перенос, восстановление, разбор инцидента) — только командой, она делает это безопасно:

    & $gitsync set-version --workdir "D:\git\base\Конфигурация" --version 120

    и, если нужно зафиксировать саму отметку в Git, добавьте --commit;

  • если VERSION пропал, а файлы источника в Git уже есть, инструмент остановится и попросит восстановить отметку — это защита от повторной выгрузки всей истории.

10.4. Первая синхронизация

Начните с ограничения на одну версию — так изменения в Git уложатся в один коммит и их легко проверить:

& $gitsync sync-all --config D:\gitsync\config\base.json --name "Конфигурация"

Полезно на первый раз добавить "limit": 1 в запись источника, затем убрать.

Когда результат устроил — полный прогон по всем источникам:

& $gitsync sync-all --config D:\gitsync\config\base.json

Что должно получиться (по одному блоку на источник)

Общий репозиторий: D:/git/base
=== Конфигурация ===
Рабочая копия подготовлена: D:\git\base\Конфигурация
2026-09-16 07:42:51,786 INFO gitsync.sync: Синхронизированная версия: 0, максимум в хранилище: 2
2026-09-16 07:42:52,574 INFO gitsync.sync: Версия 1 зафиксирована (d214426c...)
2026-09-16 07:42:53,082 INFO gitsync.sync: Версия 2 зафиксирована (b58922a2...)
Зафиксировано версий: 2 (1..2)
=== Расширение печатных форм ===
...

Первый прогон по настоящей базе идёт долго: это полная выгрузка каждой версии хранилища. Прервать можно Ctrl+C — инструмент остановится после текущей версии, а не посреди неё; повторный запуск продолжит с места обрыва, дубликатов коммитов не будет.


11. Проверка результата

# 1. Один репозиторий на всю базу: должен найтись ровно один каталог .git
(Get-ChildItem -Recurse -Force -Directory D:\git\base -Filter '.git').Count

# 2. Номер версии каждого источника
Get-Content "D:\git\base\Конфигурация\VERSION" -Encoding UTF8

# 3. История КОНКРЕТНОГО источника (главная проверка)
git -C D:\git\base log --reverse --date=format:'%Y-%m-%d %H:%M:%S' --format='%h|%an <%ae>|%ad|%s' -- "Конфигурация"

# 4. Что попало в последний коммит ЭТОГО источника
git -C D:\git\base log -1 --stat --format='%h %an %ad%n%s' --date=format:'%Y-%m-%d %H:%M:%S' -- "Конфигурация"

# 5. Ничего лишнего не изменилось
git -C D:\git\base status --porcelain --untracked-files=all

Что должно получиться

1
<?xml version="1.0" encoding="UTF-8"?>
<VERSION>2</VERSION>
d214426|Иван Иванов <i.ivanov@example.org>|2026-09-15 10:20:30|Создание хранилища
b58922a|Мария Петрова <m.petrova@example.org>|2026-09-16 08:00:00|Доработка модуля
b58922a Мария Петрова 2026-09-16 08:00:00
Доработка модуля

 Конфигурация/CommonModules/Проба.bsl | 2 +-
 Конфигурация/VERSION                 | 2 +-
 Конфигурация/Конфигурация.xml        | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)
?? Конфигурация/AUTHORS
?? "Расширение обменов/AUTHORS"
?? "Расширение печатных форм/AUTHORS"

Имена с пробелами Git показывает в кавычках — это его обычное поведение, а не признак проблемы.

Что здесь важно проверить глазами:

  1. имена и почты — те, что вы задали в AUTHORS (а не Иванов <Иванов@localhost>);
  2. даты — это даты версий хранилища, а не время запуска синхронизации;
  3. комментарии — тексты комментариев к версиям, включая многострочные;
  4. каждый коммит трогает только свой подкаталог — проверяется командой 4.

Важно: порядок коммитов в общей истории

Внутри одного источника версии всегда идут по возрастанию номера. А общий git log по всему репозиторию — это не хронология «по датам»: источники обрабатываются по очереди, поэтому после последней версии конфигурации идёт первая версия расширения, и даты в общем списке «прыгают назад». Это нормально и ожидаемо. Смотрите историю по источнику (git log -- "Конфигурация"), а общий список — только чтобы увидеть, что все источники на месте.


12. Отправка в удалённый репозиторий

Синхронизация никогда не отправляет ничего сама. Отправка — отдельная команда, и она ваша.

$branch = (git -C D:\git\base symbolic-ref --short HEAD).Trim()
git -C D:\git\base push --set-upstream origin $branch

Первый раз Git Credential Manager спросит логин к серверу Git и сохранит его в Диспетчере учётных данных Windows той учётной записи, под которой вы это сделали. Отсюда правило: настраивать доступ нужно под той же учётной записью Windows, под которой будет работать задача планировщика. Иначе задача не сможет авторизоваться.

Дальше достаточно git -C D:\git\base push.

Что должно получиться

To https://git.example.org/erp/base-sources.git
 * [new branch]      main -> main
branch 'main' set up to track 'origin/main'.

Если отправка не удалась

Симптом в выводе Что это Что делать
Could not read from remote repository / fatal: unable to access сервер недоступен, нет прав, нет сохранённого логина ничего не потеряно: коммиты лежат локально. Исправьте связь/доступ и повторите git push — уйдут те же коммиты, дубликатов не будет
! [rejected] ... (fetch first) / non-fast-forward в удалённом репозитории есть коммиты, которых нет у вас (кто-то писал туда ещё) остановитесь. Не делайте push --force и не делайте reset --hard: так теряют чужую работу или свою выгрузку. Разберитесь, откуда чужие коммиты, и согласуйте порядок работы с репозиторием
запрос логина в задаче планировщика логин сохранён под другой учётной записью Windows сохраните доступ под учётной записью задачи (см. выше)

Повторная отправка безопасна: git push переносит ровно те коммиты, которых нет на сервере. Повторный sync тоже безопасен: он смотрит на VERSION и не создаёт вторых коммитов для уже выгруженных версий (проверено).


13. Регулярный запуск: планировщик задач

13.1. Готовый скрипт (необязательный)

В репозитории программы есть готовый скрипт-обёртка examples/sync-and-push.ps1. Он делает то, что нужно регламентному запуску, и ничего лишнего:

  • не даёт двум запускам идти одновременно (свой файл блокировки);
  • проверяет свободное место до запуска (-MinFreeGB, по умолчанию 5 ГБ);
  • запускает sync-all и пишет весь вывод в суточный лог sync-ГГГГММДД.log;
  • делает git push только при успешной синхронизации и только с ключом -Push, никогда не применяет --force;
  • различает в логе и в коде возврата отказ выгрузки и отказ отправки;
  • убирает свои старые логи (файлы вида sync-ГГГГММДД.log) и ничего больше.

Пароли скрипт не трогает совсем: он берёт настройку из манифеста.

Каталоги скрипт не удаляет. Ни свои, ни чужие: имя вида run-* не доказывает, что каталог создал инструмент и что в нём прямо сейчас никто не работает, а в общем каталоге временных файлов по такому имени легко удалить чужое. Скрипт только показывает в логе, сколько старых каталогов инструмента он видит; что с ними делать, решаете вы (раздел 13.5).

Данные не становятся командами. Имя ветки скрипт читает из репозитория, а Git разрешает в имени &, %, ;, | и кавычки. Поэтому gitsync-py и git запускаются отдельными аргументами, без командного интерпретатора, и код возврата берётся у самой программы. Проверено настоящими прогонами: ветка с & отправляется как ветка, а не выполняется, неудачная отправка даёт код 5, а не «успех».

Скопируйте его рядом с настройкой и проверьте вручную:

Copy-Item D:\gitsync\program\gitsync-py\examples\sync-and-push.ps1 D:\gitsync\sync-and-push.ps1
powershell -NoProfile -ExecutionPolicy Bypass -File D:\gitsync\sync-and-push.ps1 `
    -Manifest D:\gitsync\config\base.json `
    -GitSync D:\gitsync\program\venv\Scripts\gitsync-py.exe `
    -LogDir D:\gitsync\logs
"код возврата: $LASTEXITCODE"

Что должно получиться: в конце лога и на экране — ИТОГ: УСПЕХ, код возврата 0.

Ключ -ExecutionPolicy Bypass действует только на этот запуск и ничего не меняет в настройках машины. Если политика выполнения скриптов управляется групповой политикой и запуск всё равно запрещён — не воюйте с политикой, вызывайте gitsync-py sync-all напрямую из задачи (см. 13.3). Если скрипт скопирован из сети и Windows считает его «загруженным из интернета», снимите пометку: Unblock-File D:\gitsync\sync-and-push.ps1.

Параметры скрипта:

Параметр По умолчанию Значение
-Manifest обязателен путь к JSON-манифесту
-GitSync обязателен путь к gitsync-py.exe в окружении
-LogDir обязателен каталог логов (в нём же лежит файл блокировки)
-Push выключено отправлять в удалённый репозиторий после успешной синхронизации
-Repository из ключа repository манифеста путь к выходному репозиторию
-Remote origin имя удалённого репозитория
-Branch текущая ветка репозитория какую ветку отправлять
-TempRoot из defaults.temp_root манифеста где смотреть старые временные каталоги (только смотреть)
-StaleTempDays 7 старше скольких дней считать каталог native-*/run-* старым и назвать его в логе
-KeepLogDays 30 сколько дней хранить свои логи
-MinFreeGB 5 ниже какого свободного места не запускаться

Коды возврата скрипта (их видно в планировщике):

Код Что случилось
0 всё получилось
2 ошибка в параметрах или путях (нет манифеста, нет программы, манифест не читается как JSON)
3 мало места на диске — синхронизация не запускалась
4 выгрузка не удалась (отправка не выполнялась)
5 выгрузка прошла, отправка не удалась (в том числе отклонена из-за расхождения)
6 предыдущий запуск ещё не закончился

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

13.2. Создание задачи (интерфейс планировщика)

«Планировщик заданий» → «Создать задачу» (не «простую задачу»):

  • Общие
    • Имя: GitSync: исходники базы.
    • Переключатель: «Выполнять вне зависимости от регистрации пользователя» — иначе задача будет ждать, пока кто-нибудь войдёт в систему.
    • Учётная запись («Изменить…»): та же, под которой вы сохранили доступ к серверу Git и которой выдали права на файл пароля.
    • Флажок «Не сохранять пароль» должен быть снят: без сохранённого пароля у задачи не будет доступа к сети, и git push не пройдёт.
    • «Выполнить с наивысшими правами» включать не нужно.
  • Триггеры: например, ежедневно каждый час. Не ставьте интервал меньше, чем длится один прогон.
  • Действия → «Запуск программы»:
    • Программа: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe

    • Аргументы (одной строкой):

      -NoProfile -ExecutionPolicy Bypass -File "D:\gitsync\sync-and-push.ps1" -Manifest "D:\gitsync\config\base.json" -GitSync "D:\gitsync\program\venv\Scripts\gitsync-py.exe" -LogDir "D:\gitsync\logs" -Push
      
    • Рабочая папка («Начать в»): D:\gitsync

  • Параметры
    • «Если задача уже выполняется, то применяется следующее правило»: не запускать новый экземпляр.
    • «Останавливать задачу, выполняемую дольше»: поставьте заведомо больший срок, чем обычный прогон (например, 8 часов), иначе планировщик убьёт нормальную работу.

13.3. Запуск без скрипта

Если скрипт использовать нельзя, задача может вызывать программу напрямую:

  • Программа: D:\gitsync\program\venv\Scripts\gitsync-py.exe
  • Аргументы: sync-all --config "D:\gitsync\config\base.json"
  • Рабочая папка: D:\gitsync

В этом случае вы сами отвечаете за лог, отправку в удалённый репозиторий и уборку временных файлов. Собственного лог-файла у программы нет: она пишет в консоль, поэтому вывод надо перенаправлять. В PowerShell 5.1 надёжнее всего так (запись именно в UTF-8, в один файл, с сохранением кода возврата):

$env:PYTHONUTF8 = '1'
cmd /c '"D:\gitsync\program\venv\Scripts\gitsync-py.exe" sync-all --config "D:\gitsync\config\base.json" >> "D:\gitsync\logs\sync.log" 2>&1'
"код возврата: $LASTEXITCODE"

Почему через cmd /c: журнал программы идёт в «поток ошибок», и при перенаправлении потоков средствами PowerShell (2>&1, Tee-Object) вместе с $ErrorActionPreference = 'Stop' запуск падает на первой же строке журнала, а Tee-Object к тому же пишет файл в UTF-16.

13.4. Проверка задачи

Get-ScheduledTaskInfo -TaskName 'GitSync: исходники базы' |
    Select-Object TaskName, LastRunTime, LastTaskResult, NextRunTime

Что должно получиться: LastTaskResult : 0. Любое другое число — отказ; расшифровка в таблице кодов выше (в интерфейсе планировщика код показывается в шестнадцатеричном виде: 0x4, 0x5 …). Подробности всегда в логе за этот день: Get-Content D:\gitsync\logs\sync-20260916.log -Encoding UTF8 -Tail 40.

13.5. Диск: за чем следить

Регулярный запуск сам по себе не растёт бесконечно, но за четырьмя вещами надо следить:

Что растёт Где Что делать
Промежуточные выгрузки версий D:\gitsync\temp\run-* удаляются самим инструментом после каждой версии; на время работы держите свободным jobs × (размер выгрузки + .cf)
Протоколы конфигуратора и временные базы D:\gitsync\temp\native-* после успешного прогона инструмент снимает свой каталог сам. Остаются два случая: отказ (внутри — протоколы /Out, на которые ссылается сообщение об ошибке) и --keep-temp. Эти каталоги убирает ваш регламент: скрипт из 13.1 не удаляет их сам
Логи D:\gitsync\logs\sync-ГГГГММДД.log скрипт хранит -KeepLogDays дней и удаляет только файлы этого вида
Сам репозиторий D:\git\base растёт с историей базы; это нормально, планируйте место с запасом

Скрипт из 13.1 пишет в лог, сколько каталогов старше -StaleTempDays он видит, и на этом останавливается. Так и задумано: имя run-* или native-* — это соглашение об именовании, а не доказательство принадлежности. В общий temp такие же имена может писать что угодно ещё, а каталог с подходящим именем может прямо сейчас использовать другой запуск.

Уборка — ручная, в два шага. Сначала посмотрите, что именно предлагается удалить:

$старые = Get-ChildItem D:\gitsync\temp -Directory |
    Where-Object { ($_.Name -like 'native-*' -or $_.Name -like 'run-*') -and
                   $_.LastWriteTime -lt (Get-Date).AddDays(-7) }
$старые | Select-Object Name, LastWriteTime

Убедились, что в списке только ваши каталоги и что синхронизация сейчас не работает, — удаляйте:

$старые | Remove-Item -Recurse -Force

Что стоит сделать один раз, чтобы список всегда был честным: отведите инструменту отдельный каталог временных файлов (defaults.temp_root), которым не пользуется ничего больше. Тогда «старые каталоги инструмента» — это действительно каталоги инструмента.

Ключ --keep-temp нужен только для разбора инцидента: он оставляет все временные файлы, включая выгрузки.

Ещё один служебный след — файлы-блокировки сеансов хранилища в профиле учётной записи (%USERPROFILE%\.gitsync\repository-sessions\*.lock, по 26 байт). Они нужны, чтобы два одновременных чтения одного хранилища под одним пользователем не мешали друг другу. Удалять их не нужно; учтите только, что задачи под разными учётными записями Windows друг о друге не знают.


14. Повседневные операции

Добавить третье (четвёртое, пятое…) расширение

  1. Узнайте в конфигураторе точное имя расширения и адрес его хранилища.

  2. Допишите в storages ещё одну однотипную запись (уникальные name и subtree):

    { "name": "Расширение ЭДО", "subtree": "Расширение ЭДО",
      "storage_path": "D:/storages/base-edo", "extension": "РасширениеЭДО" }
  3. Прогоните только новый источник — остальные не будут даже прочитаны:

    & $gitsync sync-all --config D:\gitsync\config\base.json --name "Расширение ЭДО"
  4. Проверьте: появился подкаталог со своими AUTHORS/VERSION, коммиты трогают только его. При желании поправьте AUTHORS нового источника и прогоните заново — но помните: правка действует только на будущие коммиты, поэтому лучше сделать это между шагами 2 и 3 (запустите init отдельно, поправьте AUTHORS, затем sync-all --name ...).

Подкаталоги источников не должны вкладываться друг в друга (Расширения и Расширения/ЭДО одновременно — нельзя). Такую настройку инструмент отклонит: иначе выгрузка внешнего источника удалила бы файлы вложенного.

Временно отключить источник

Добавьте в запись "disable": true. В журнале будет === Имя: отключено в конфигурации, пропускаю ===, остальные источники отработают как обычно.

Поменять подписи авторов

Отредактируйте AUTHORS нужного источника. Подействует на новые коммиты. Уже созданные коммиты не меняются.

Перенести настроенную синхронизацию на другую машину

  1. Перенесите (или заново клонируйте) выходной репозиторий вместе с файлами VERSION и AUTHORS.
  2. Установите программу по шагу 5, заново создайте файл пароля и права.
  3. Проверьте core.autocrlf/core.quotepath в новом клоне (шаг 7.4).
  4. Сохраните доступ к серверу Git под учётной записью новой задачи.
  5. Запустите sync-all — он продолжит с номера из VERSION, а не с начала.

Хранилище пересоздали (номера версий начались заново)

Инструмент это заметит и остановится сам: Версия в git (120) больше версии хранилища (3) на 118. Возможно, хранилище пересоздали или обрезали. Решение принимает человек: либо синхронизировать новое хранилище в новый подкаталог (или новый репозиторий), либо, если вы точно понимаете последствия, выставить номер командой set-version.


15. Кодировки: три правила

Windows PowerShell 5.1 и Python здесь требуют разного, поэтому правила простые и жёсткие: два файла, где кодировка критична, и два, где BOM допустим.

Файл Кодировка Что будет при ошибке
Файл пароля UTF-8 без BOM (или чистый ASCII) BOM станет частью пароля (проверено: длина пароля +1 символ), конфигуратор откажет в аутентификации, а вы будете искать причину в правах
Скрипты *.ps1 с русским текстом UTF-8 с BOM PowerShell 5.1 прочитает файл как ANSI: русские буквы превратятся в мусор и скрипт не запустится с UnexpectedToken
Манифест *.json UTF-8, BOM допустим ничего: манифест читается как utf-8-sig, поэтому файл, сохранённый «Блокнотом» или Out-File из PowerShell 5.1, принимается как есть (проверено)
AUTHORS UTF-8, BOM допустим ничего: BOM здесь корректно пропускается (проверено)

Привычку сохранять манифест без BOM это не отменяет: так файл одинаково читают любые инструменты, включая чужие. Но если BOM там уже есть — переделывать не нужно, и ошибка в JSON означает именно ошибку в JSON.

Как сохранить без BOM (работает и в PowerShell 5.1, и в 7):

$text = Get-Content D:\gitsync\config\base.json -Raw -Encoding UTF8
[System.IO.File]::WriteAllText('D:\gitsync\config\base.json', $text, (New-Object System.Text.UTF8Encoding($false)))

Ключ -Encoding UTF8 в первой строке обязателен: без него PowerShell 5.1 прочитает файл как ANSI и кириллица в путях превратится в мусор.

Как проверить, есть ли BOM (ef bb bf в начале — есть, 7b 0a 20 или похожее — нет):

((([System.IO.File]::ReadAllBytes('D:\gitsync\config\base.json'))[0..2]) | ForEach-Object { $_.ToString('x2') }) -join ' '

Не используйте Set-Content -Encoding UTF8 в PowerShell 5.1 для JSON и файла пароля: он добавляет BOM. «Блокнот» в актуальных Windows 10/11 сохраняет UTF-8 без BOM, если в списке кодировок выбрать именно «UTF-8» (а не «UTF-8 с BOM»).


16. Если что-то не работает

Симптом (что видно) Причина Что делать
Для нативного бэкенда укажите --v8-path не указан путь к 1С добавьте v8_path в манифест или ключ --v8-path
FileNotFoundError: [WinError 2] Не удается найти указанный файл (длинная «простыня» Python) неверный путь к 1cv8.exe, к файлу пароля или не найден git проверьте по очереди: Test-Path для v8_path и файла пароля, затем git --version в том же окне; для задачи планировщика — что git есть в PATH учётной записи задачи
Переменная окружения <...> пуста или не задана окно PowerShell новое или переменная не задавалась задайте пароль как в шаге 8.1; для задачи используйте файл пароля
Конфигуратор просит пароль / Конфигуратор завершился с кодом ... при правильном пароле в файле пароля BOM или лишние символы пересохраните файл без BOM (раздел 15)
Конфигуратор завершился с кодом N: ... /ConfigurationRepositoryP *** ... конфигуратор отказался: неверный пользователь/пароль, нет прав на хранилище, неверное имя расширения, нет лицензии откройте протокол конфигуратора: путь к нему виден в сообщении после /Out (файл в D:\gitsync\temp\native-*\designer-out\) — остаётся после отказа именно он. Остальные пути, которые сообщение повторяет за командной строкой конфигуратора (worker-*\ib, storage-report-*.mxl), одноразовые и к этому моменту уже удалены — так и задумано. Проверьте вход в хранилище конфигуратором вручную под тем же пользователем
Конфигуратор не завершился за 3600 с зависший или очень долгий вызов увеличьте designer_timeout, проверьте загрузку сервера; повторы для таймаута намеренно не делаются
Пользователь уже аутентифицирован в хранилище тем же пользователем хранилища одновременно работает кто-то ещё (человек в конфигураторе или другая задача) одновременные чтения одного хранилища одной задачей выстраиваются в очередь автоматически; согласуйте внешних потребителей, не используйте одного пользователя хранилища для людей и для задачи
В рабочей копии <...> есть чужие незафиксированные изменения: ... в подкаталоге источника кто-то правил файлы руками зафиксируйте или уберите правки (git status, git add+git commit или git checkout -- <файл>). Ключ allow_dirty — только если это заведомо ваши артефакты
Файл <...\VERSION> отсутствует, хотя в git уже есть файлы этого источника отметка версии потеряна верните её из Git (git checkout -- "Конфигурация/VERSION") или задайте номер set-version. Не начинайте с нуля: это повторит всю историю
Файл <...\VERSION> не содержит номер версии: '...' файл испорчен/отредактирован set-version --version N, где N — номер последней выгруженной версии (его видно в git log)
Версия в git (X) больше версии хранилища (Y) хранилище пересоздали или обрезали см. «Хранилище пересоздали»
Цель <...\.git\gitsync-py.lock> уже обрабатывается; ожидание N с истекло параллельно работает другой запуск по этому репозиторию нормальная защита. Увеличьте lock_timeout, разведите расписания, включите «не запускать новый экземпляр»
Индекс Git заблокирован файлом <...index.lock> с репозиторием работает другой процесс Git (или чей-то зависший клиент) дождитесь его завершения. Инструмент чужую блокировку не снимает — и вы не снимайте, пока не убедились, что процесс мёртв
Индекс Git занят незавершённой транзакцией источника <...> предыдущий запуск другого источника прервали запустите синхронизацию того источника: он сам аккуратно снимет свою незавершённую транзакцию
Каталог временных файлов <...> находится внутри рабочей копии temp_root указан внутри выходного репозитория вынесите его наружу (раздел 4)
Хранилище №N: неизвестные ключи ... / Неизвестные ключи конфигурации: ... опечатка в названии ключа манифеста сверьтесь с таблицей ключей
Файл <...> не является корректным JSON: ... лишняя запятая, кавычки-«ёлочки» из Word, обрезанный файл правьте в обычном текстовом редакторе; BOM тут ни при чём — он принимается
Каталоги хранилищ <A> и <B> вложены друг в друга подкаталоги источников пересекаются разнесите subtree по независимым папкам
В git status/git log русские имена как \320\232\320\276... в этом репозитории не выключено экранирование путей git -C D:\git\base config core.quotepath false
Русский текст в логе — «кракозябры» вывод писался не в UTF-8 $env:PYTHONUTF8 = '1' перед запуском и перенаправление через cmd /c ... 2>&1 (раздел 13.3); читайте лог как Get-Content ... -Encoding UTF8
Скрипт .ps1 не запускается: UnexpectedToken, русский текст в ошибке искажён файл сохранён как UTF-8 без BOM пересохраните с BOM (раздел 15)
Новых версий нет, хотя в хранилище есть версии номер в VERSION уже равен максимальному, либо читается не то хранилище сверьте VERSION и storage_path; посмотрите строку журнала Синхронизированная версия: X, максимум в хранилище: Y
Внутри репозитория несколько каталогов .git синхронизацию запустили до создания общего репозитория создайте общий репозиторий и перенастройте: источник должен быть подкаталогом уже существующего репозитория (шаг 7)
Отправка не проходит: [rejected] ... fetch first в удалённый репозиторий писали ещё откуда-то см. «Если отправка не удалась». Ни --force, ни reset --hard
Задача планировщика завершилась, а коммиты остались только локально отправка не выполнялась (-Push не задан) или не удалась (код 5) посмотрите лог: отказ выгрузки и отказ отправки различаются явно. Локальные коммиты в любом случае целы, повторная отправка не создаёт дублей
Соседний источник «поехал» после чужой правки в репозитории кто-то менял файлы в подкаталоге источника извне правки внутри подкаталога источника — запрещены: источник считает своим всё содержимое своей папки. Свои файлы держите в корне репозитория или в отдельной папке, которая не является источником

Коды возврата самой программы:

Код Значение
0 успех (в том числе «новых версий нет»)
1 сбой в процессе работы: не выгрузилась версия, грязная рабочая копия, занятая цель, испорченный VERSION, ошибка после коммита
2 не приняты параметры или настройка: нет --v8-path, пароль в командной строке, ошибки в манифесте
130 остановлено по Ctrl+C (после завершения текущей версии)

Любой код, кроме 0, означает «прогон не удался»; в планировщике это и есть признак отказа.


17. Резервные копии

Ваши данные здесь — это выходной репозиторий. Перед первым прогоном по настоящей базе и перед любыми опытами с set-version:

git -C D:\git\base bundle create D:\backup\base-до-изменений.bundle --all

Один файл, из которого репозиторий восстанавливается полностью: git clone D:\backup\base-до-изменений.bundle D:\git\base-restored.

Что ещё стоит скопировать: манифест (D:\gitsync\config), файлы AUTHORS каждого источника (они не попадают в Git автоматически). Файл пароля не копируйте в общие хранилища.

Хранилище 1С инструмент только читает, но общее правило не отменяется: опыты ставьте на тестовом хранилище и на копии репозитория.


18. Чек-лист приёмки

Отметьте всё до передачи в регламент:

  • gitsync-py --version работает из окружения, установленного по шагу 5;
  • репетиция на учебной фикстуре прошла, коммиты с авторами и датами появились;
  • выходной репозиторий создан приватным и клонирован; git symbolic-ref --short HEAD показывает ожидаемую ветку;
  • в репозитории заданы core.autocrlf=false и core.quotepath=false;
  • манифест разбирается: проверка --name "нет такого источника" даёт понятную ошибку;
  • секреты лежат вне репозитория; файл пароля без BOM, права выданы только задаче и администраторам; setx не использовался;
  • temp_root вне репозитория, на диске есть запас места;
  • AUTHORS каждого источника отредактирован до первой синхронизации;
  • первый прогон сделан с ограничением (limit/--name) и проверен глазами;
  • в git log -- "<подкаталог>" совпадают автор, почта, дата и комментарий версий;
  • каждый коммит источника трогает только свой подкаталог (git show --stat);
  • повторный запуск даёт «Новых версий нет» и не создаёт новых коммитов;
  • git push выполнен под той учётной записью Windows, под которой будет работать задача;
  • задача планировщика: правильная учётная запись, «не запускать новый экземпляр», рабочая папка, лог пишется, LastTaskResult = 0;
  • проверено поведение при отказе: остановленный сервер Git → выгрузка успешна, отправка нет, локальные коммиты целы, повторный запуск всё отправляет;
  • сделана резервная копия репозитория (git bundle) и зафиксировано, где она лежит.

19. Куда смотреть дальше

  • README.md — краткое описание и список команд.
  • docs/monorepo.md — гарантии и границы раскладки «один репозиторий базы».
  • docs/compatibility-matrix.md — что перенесено из оригинального gitsync, что нет и что не проверялось.
  • docs/migration.md — переход с gitsync на OneScript, если он у вас уже работает.
  • docs/native-session-concurrency.md — как устроена очередь одновременных чтений хранилища.
  • docs/plugins.md — плагины на Python и их границы.