Это руководство рассчитано на администратора 1С, который не знает Python и не обязан его знать. Все команды даны для Windows PowerShell (тот, что открывается по «Пуск → Windows PowerShell»). Каждый шаг заканчивается блоком «Что должно получиться»: если видите не это — не идите дальше, а посмотрите раздел Если что-то не работает.
Примеры путей — условные (D:\gitsync\..., D:\git\base). Подставляйте свои. Примеры вывода взяты
из настоящих прогонов, в них заменены только пути и имена.
Есть два разных репозитория 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 |
Если хочется сначала общей картины: вот весь путь целиком. Каждая строка — ссылка на подробный шаг.
| № | Что делаете | Сколько занимает |
|---|---|---|
| 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 мин |
| Что | Требование | Как проверить |
|---|---|---|
| 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 | не проверялись |
Вывод для приёмки: начинайте с файлового хранилища или сначала проверьте серверное на копии. Первый прогон делайте на тестовом хранилище, а не на рабочем.
Четыре разных места, и их нельзя смешивать:
| Что | Пример пути | Почему отдельно |
|---|---|---|
| Программа (исходники + окружение 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) проще держать латиницей: меньше поводов для ошибок при копировании команд.
Ссылку на репозиторий программы вам даёт тот, кто её публикует. Пока репозиторий приватный,
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 делает это сам.
Прежде чем трогать 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.
Порядок именно такой: сначала создать выходной репозиторий, потом запускать синхронизацию. Если запустить синхронизацию по подкаталогу, когда общего репозитория ещё нет, инструмент честно создаст репозиторий внутри подкаталога — и вместо одной истории базы получится несколько отдельных репозиториев.
Руками, в веб-интерфейсе вашего сервера (GitLab/GitHub/Gitea/Bitbucket):
- видимость — приватный (в выгрузке лежит ваша конфигурация целиком);
- без файлов инициализации (без README, без .gitignore) — репозиторий должен быть пустым;
- запишите его адрес, например
https://git.example.org/erp/base-sources.git.
git clone https://git.example.org/erp/base-sources.git D:\git\baseДля пустого репозитория Git честно предупредит warning: You appear to have cloned an empty repository. — так и должно быть.
Не предполагайте main: у разных серверов и у разных настроек Git ветка по умолчанию разная
(main или master). Спросите у самого репозитория:
git -C D:\git\base symbolic-ref --short HEADЧто должно получиться: одна строка, например main. Это имя понадобится при отправке.
Инструмент выставляет их сам, только если создаёт репозиторий с нуля. Ваш клон он не переделывает, поэтому задайте их один раз руками:
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
Файлы в корне репозитория инструменту не мешают — он работает только внутри подкаталогов источников. Для своих коммитов 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 "описание репозитория"Пароль нельзя передавать аргументом командной строки — программа это прямо запрещает, потому что аргументы видны всем процессам в системе. Есть два разрешённых способа:
| Способ | Для чего | Ключ |
|---|---|---|
| Переменная окружения | запуск руками из открытого окна PowerShell | --storage-password-env ИМЯ / "storage_password_env" |
| Файл с паролем | запуск по расписанию, когда спросить некого | --storage-password-file ПУТЬ / "storage_password_file" |
Если у пользователя хранилища пустой пароль — не указывайте ни того, ни другого.
$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.
У задачи планировщика нет человека, который введёт пароль, поэтому остаётся файл. Важно понимать честно: файл лежит в открытом виде. Защита — только права на файл. Поэтому:
- файл вне выходного репозитория (иначе он попадёт в 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 ***, причём замаскирован и вывод самого конфигуратора (проверено).
Все хранилища базы описываются одним файлом 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.jsonrepository— путь к общему выходному репозиторию. Если его ещё нет, он будет создан (git init -b main), но лучше создать заранее, как в шаге 7.defaults— значения, общие для всех источников.storages— список источников; значения в записи перекрываютdefaults.
Пути в JSON пишите с прямыми слэшами (D:/gitsync/temp) — так не нужно думать об экранировании.
Обратные слэши тоже допустимы, но их надо удваивать (D:\\gitsync\\temp).
Верхний уровень: 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) |
Это самая частая путаница. Значения независимы:
extension— имя расширения, как оно называется в 1С (свойство «Имя» объекта метаданных расширения, латиница/кириллица без пробелов, напримерРасширениеПечатныхФорм). Именно оно уходит конфигуратору как-Extension. Ошибётесь — конфигуратор вернёт ошибку, а не пустую выгрузку.subtree— имя папки в вашем репозитории, любое удобное для чтения человеком, можно с пробелами:Расширение печатных форм.
Где посмотреть точное имя: конфигуратор → «Конфигурация → Расширения конфигурации» → колонка «Имя» (не «Синоним»!). Синоним — это то, что видит пользователь; для настройки нужно «Имя».
Для основной конфигурации ключ extension не указывают вообще.
Схема проверяется до любых действий, поэтому опечатку видно сразу:
& "D:\gitsync\program\venv\Scripts\gitsync-py.exe" sync-all --config D:\gitsync\config\base.json --name "нет такого источника"Что должно получиться: сообщение Ошибка: В конфигурации нет хранилищ: нет такого источника
и код возврата 2 — значит сам файл разобран и схема принята. Если вместо этого пришла жалоба на
ключ — сначала исправьте её.
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>
Это важный момент. Подписи берутся из 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 "таблицы авторов источников"VERSION — это отметка «до какой версии хранилища мы дошли». Инструмент опирается на неё, чтобы
продолжить с места обрыва и не сделать дубли коммитов. Поэтому:
-
не правьте
VERSIONв блокноте «чтобы перезалить»: занижение номера повторит уже выгруженные версии, завышение — молча пропустит настоящие; -
если номер действительно нужно изменить (перенос, восстановление, разбор инцидента) — только командой, она делает это безопасно:
& $gitsync set-version --workdir "D:\git\base\Конфигурация" --version 120
и, если нужно зафиксировать саму отметку в Git, добавьте
--commit; -
если
VERSIONпропал, а файлы источника в Git уже есть, инструмент остановится и попросит восстановить отметку — это защита от повторной выгрузки всей истории.
Начните с ограничения на одну версию — так изменения в 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 — инструмент остановится после текущей версии, а не посреди неё; повторный запуск продолжит с места обрыва, дубликатов коммитов не будет.
# 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 показывает в кавычках — это его обычное поведение, а не признак проблемы.
Что здесь важно проверить глазами:
- имена и почты — те, что вы задали в
AUTHORS(а неИванов <Иванов@localhost>); - даты — это даты версий хранилища, а не время запуска синхронизации;
- комментарии — тексты комментариев к версиям, включая многострочные;
- каждый коммит трогает только свой подкаталог — проверяется командой 4.
Внутри одного источника версии всегда идут по возрастанию номера. А общий git log по всему
репозиторию — это не хронология «по датам»: источники обрабатываются по очереди, поэтому после
последней версии конфигурации идёт первая версия расширения, и даты в общем списке «прыгают назад».
Это нормально и ожидаемо. Смотрите историю по источнику (git log -- "Конфигурация"), а общий
список — только чтобы увидеть, что все источники на месте.
Синхронизация никогда не отправляет ничего сама. Отправка — отдельная команда, и она ваша.
$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 и не создаёт вторых коммитов для уже
выгруженных версий (проверено).
В репозитории программы есть готовый скрипт-обёртка
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 и расхождение истории.
«Планировщик заданий» → «Создать задачу» (не «простую задачу»):
- Общие
- Имя:
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 часов), иначе планировщик убьёт нормальную работу.
Если скрипт использовать нельзя, задача может вызывать программу напрямую:
- Программа:
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.
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.
Регулярный запуск сам по себе не растёт бесконечно, но за четырьмя вещами надо следить:
| Что растёт | Где | Что делать |
|---|---|---|
| Промежуточные выгрузки версий | 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 друг о друге не знают.
-
Узнайте в конфигураторе точное имя расширения и адрес его хранилища.
-
Допишите в
storagesещё одну однотипную запись (уникальныеnameиsubtree):{ "name": "Расширение ЭДО", "subtree": "Расширение ЭДО", "storage_path": "D:/storages/base-edo", "extension": "РасширениеЭДО" } -
Прогоните только новый источник — остальные не будут даже прочитаны:
& $gitsync sync-all --config D:\gitsync\config\base.json --name "Расширение ЭДО"
-
Проверьте: появился подкаталог со своими
AUTHORS/VERSION, коммиты трогают только его. При желании поправьтеAUTHORSнового источника и прогоните заново — но помните: правка действует только на будущие коммиты, поэтому лучше сделать это между шагами 2 и 3 (запуститеinitотдельно, поправьтеAUTHORS, затемsync-all --name ...).
Подкаталоги источников не должны вкладываться друг в друга (Расширения и
Расширения/ЭДО одновременно — нельзя). Такую настройку инструмент отклонит: иначе выгрузка
внешнего источника удалила бы файлы вложенного.
Добавьте в запись "disable": true. В журнале будет
=== Имя: отключено в конфигурации, пропускаю ===, остальные источники отработают как обычно.
Отредактируйте AUTHORS нужного источника. Подействует на новые коммиты. Уже созданные
коммиты не меняются.
- Перенесите (или заново клонируйте) выходной репозиторий вместе с файлами
VERSIONиAUTHORS. - Установите программу по шагу 5, заново создайте файл пароля и права.
- Проверьте
core.autocrlf/core.quotepathв новом клоне (шаг 7.4). - Сохраните доступ к серверу Git под учётной записью новой задачи.
- Запустите
sync-all— он продолжит с номера изVERSION, а не с начала.
Инструмент это заметит и остановится сам:
Версия в git (120) больше версии хранилища (3) на 118. Возможно, хранилище пересоздали или обрезали. Решение принимает человек: либо синхронизировать новое хранилище в новый подкаталог
(или новый репозиторий), либо, если вы точно понимаете последствия, выставить номер командой
set-version.
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»).
| Симптом (что видно) | Причина | Что делать |
|---|---|---|
Для нативного бэкенда укажите --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, означает «прогон не удался»; в планировщике это и есть признак отказа.
Ваши данные здесь — это выходной репозиторий. Перед первым прогоном по настоящей базе и перед
любыми опытами с 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С инструмент только читает, но общее правило не отменяется: опыты ставьте на тестовом хранилище и на копии репозитория.
Отметьте всё до передачи в регламент:
-
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) и зафиксировано, где она лежит.
- README.md — краткое описание и список команд.
- docs/monorepo.md — гарантии и границы раскладки «один репозиторий базы».
- docs/compatibility-matrix.md — что перенесено из оригинального gitsync, что нет и что не проверялось.
- docs/migration.md — переход с gitsync на OneScript, если он у вас уже работает.
- docs/native-session-concurrency.md — как устроена очередь одновременных чтений хранилища.
- docs/plugins.md — плагины на Python и их границы.