--- url: /template-sync-strategy/overview.md description: >- Управляемое обновление проектов от шаблона через чистую ветку template, временные sync-ветки и PR/MR. --- # Template Sync Strategy Template Sync Strategy описывает процесс, при котором приложение создаётся от шаблона и дальше регулярно получает обновления шаблона без ручного копирования файлов. Основной маршрут: ```text templates/master -> template -> sync/* -> master ``` Где: * `templates/master` — основная ветка внешнего репозитория шаблона. * `template` — чистый слепок шаблона внутри репозитория приложения. * `sync/*` — временная ветка, где шаблон накладывается на приложение. * `master` — основная ветка приложения. ## Задача Шаблон хорошо решает старт проекта: приносит CI/CD, Dockerfile, зависимости, линтер, сборку, структуру и базовую документацию. Но после старта приложения расходятся: где-то обновили CI, где-то забыли, где-то сделали локальную кастомизацию. Стратегия нужна, чтобы шаблон оставался общей технической базой не только в первый день проекта, но и на всём жизненном цикле приложения. ## Главный принцип Ветка `template` должна оставаться чистым слепком оригинального шаблона. В неё нельзя коммитить изменения приложения и нельзя решать конфликты. Все конфликтные решения выполняются только во временных ветках `sync/*`. ## Состав документации * [Зачем это нужно](./concepts/why.md) — какие проблемы появляются без update-flow. * [Модель веток](./concepts/model.md) — роли `templates/master`, `template`, `sync/*` и `master`. * [Правила процесса](./concepts/rules.md) — ограничения, которые удерживают схему чистой. * [Новый проект от шаблона](./setup/clean-repository.md) — старт приложения с правильной историей. * [Миграция существующего master](./setup/existing-master-migration.md) — одноразовое связывание несвязанных историй. * [Обычное обновление шаблона](./workflows/update-template.md) — регулярный рабочий процесс. * [Решение конфликтов](./workflows/resolve-conflicts.md) — где и как совместить шаблон с приложением. * [Review и merge](./workflows/review-and-merge.md) — как доставлять sync-ветку в `master`. * [Памятка](./reference/cheatsheet.md) — короткий набор команд. * [Troubleshooting](./reference/troubleshooting.md) — типовые ошибки и диагностика. * [Глоссарий](./reference/glossary.md) — основные термины. --- --- url: /template-sync-strategy/concepts/why.md description: >- Почему шаблону нужен процесс обновления, а не только быстрый старт нового проекта. --- # Зачем это нужно Шаблон закрывает повторяющуюся техническую базу проекта: CI/CD, Dockerfile, зависимости, lint, build, структуру каталогов и базовую документацию. Это снимает рутину на старте. Команде не нужно каждый раз заново собирать одинаковый технический каркас. ## Проблема после старта Создать проект легко. Поддерживать 10-20 проектов сложнее. Сначала проекты похожи. Потом они начинают расходиться: * В одном проекте обновили CI, в другом забыли. * В одном проекте Dockerfile остался из шаблона, в другом его локально поправили. * В одном проекте зависимости уже свежие, в другом остались старые версии. * В одном проекте изменения шаблона перенесли руками, в другом потеряли. Без процесса обновления шаблон перестаёт быть общей основой. Он остаётся только способом быстро создать первый коммит. ## Что ломается без стратегии Когда шаблон нельзя нормально обновлять: * проекты начинают жить своей жизнью; * граница между шаблоном и приложением теряется; * обновления превращаются в ручное копирование; * конфликты решаются прямо в рабочих ветках; * становится непонятно, какой проект на какой версии шаблона; * Git-история перестаёт быть источником правды. Это особенно больно, когда приложений много. Для одного проекта ручной перенос ещё можно пережить. Для набора проектов нужен единый маршрут обновления. ## Цель стратегии Стратегия не пытается убрать конфликты полностью. Она делает так, чтобы конфликты возникали в предсказуемом месте, проходили review и не ломали чистую ветку шаблона. Главная формулировка: > Шаблон должен обновляться так же контролируемо, как обычная фича: через ветку, проверку и PR/MR. --- --- url: /template-sync-strategy/concepts/model.md description: Роли веток и remote в стратегии обновления проекта от шаблона. --- # Модель веток Целевая схема: ```text templates/master -> template -> sync/* -> master ``` Это логическая модель ответственности. Она не требует физически разделять файлы шаблона и приложения по папкам. ## templates/master `templates/master` — это `master` из репозитория шаблона. В репозитории приложения он доступен через remote `templates`: ```bash git remote add templates git fetch templates ``` Этот remote считается источником обновлений шаблона. ## template `template` — чистый слепок шаблона внутри репозитория приложения. Его задача — показать, какая версия шаблонной базы сейчас доступна приложению. В `template` нельзя коммитить руками изменения приложения. Эта ветка обновляется только из `templates/master`. ## master `master` — основная ветка приложения. Она содержит: * базу шаблона; * продуктовый код; * локальные настройки приложения; * историю применения обновлений шаблона. `master` не используется как место ручного решения конфликтов при обновлении шаблона. ## sync/\* `sync/*` — временная ветка для обновления приложения от шаблона. Она создаётся от актуального `origin/master`, после чего в неё вливается `origin/template`. Пример: ```bash git fetch origin git switch -c sync/update-template-v2 origin/master git merge origin/template ``` Если появляются конфликты, они решаются именно в этой ветке. ## Почему нужен отдельный sync-слой Нельзя безопасно использовать `template` как source branch для прямого PR/MR в `master`: если возникнет конфликт, решение может попасть в `template`. После этого `template` перестанет быть чистым слепком шаблона. Git начнёт видеть в ней не только шаблон, но и локальные решения конкретного приложения. `sync/*` можно пачкать conflict resolve-коммитами, проверками и правками совместимости. Эта ветка временная и удаляется после merge. --- --- url: /template-sync-strategy/concepts/rules.md description: >- Набор правил, который удерживает template чистой, а обновления шаблона контролируемыми. --- # Правила процесса Небольшой набор правил удерживает схему чистой. ## Делаем * `template` обновляем только из `templates/master`. * `sync/*` создаём от `origin/master`. * `origin/template` вливаем в `sync/*`, а не напрямую в `master`. * Конфликты решаем только в `sync/*`. * `sync/* -> master` вливаем через PR/MR. * Для sync-PR/MR отключаем squash. ## Не делаем * Не правим `template` руками. * Не коммитим изменения приложения в `template`. * Не мержим `template -> master` напрямую. * Не решаем конфликты в `master`. * Не включаем squash для `sync/* -> master`. ## Почему squash нельзя Squash может уничтожить нормальную связь истории `master` с историей `template`. Git использует историю, чтобы понимать, какие изменения шаблона уже были доставлены в приложение. Если результат обновления шаблона превратить в один squash-коммит, связь с исходными коммитами шаблона станет хуже или исчезнет. Для sync-PR/MR допустимы: ```text fast-forward merge = хорошо merge commit = допустимо squash merge = нельзя ``` ## Почему template нельзя пачкать `template` — эталонный слепок оригинального шаблона. Если в неё попадает локальное решение конфликта или изменение приложения, она перестаёт отвечать на вопрос: “какая версия шаблона сейчас подключена к приложению?”. После этого ломается главная граница ответственности: шаблон отдельно, приложение отдельно, конфликтная зона отдельно. --- --- url: /template-sync-strategy/setup/clean-repository.md description: Старт нового приложения от шаблонного репозитория с правильной историей веток. --- # Новый проект от шаблона Этот сценарий подходит, когда репозиторий приложения ещё пустой или его можно безопасно пересоздать от шаблона. Целевая модель: ```text templates/master -> template -> sync/* -> master ``` ## Условия Есть два репозитория: ```text template repo = репозиторий шаблона app repo = репозиторий приложения ``` В обоих репозиториях основная ветка называется `master`. ## Подготовить шаблон В репозитории шаблона: ```bash cd /path/to/template-repo git switch master ``` Если это пустой репозиторий, добавьте первый файл и запушьте `master`: ```bash printf "# Template Repository\n\nBase template version: v1\n" > README.md git add README.md git commit -m "docs: добавить базовый шаблон" git push -u origin master ``` ## Подключить шаблон в приложении В репозитории приложения: ```bash cd /path/to/app-repo git remote add templates git fetch templates ``` Создайте ветку `template` от шаблона: ```bash git switch -c template templates/master git push -u origin template ``` Создайте ветку приложения `master` от `template`: ```bash git switch -c master template ``` Добавьте слой приложения: ```bash mkdir -p app printf "Application code v1\n" > app/app.txt git add app/app.txt git commit -m "feat: добавить слой приложения" git push -u origin master ``` После этого история выглядит так: ```text template: T1 master: T1---A1 ``` Где `T1` — коммит шаблона, а `A1` — коммит приложения. ## Настроить pull и push для template Можно сделать так, чтобы на ветке `template`: ```text git pull тянул из templates/master git push пушил в origin/template ``` Команды: ```bash git config branch.template.remote templates git config branch.template.merge refs/heads/master git config branch.template.pushRemote origin ``` Дополнительно можно запретить случайный push в репозиторий шаблона: ```bash git remote set-url --push templates DISABLED ``` ## Дальше После первичной настройки постоянные ветки такие: ```text template = чистый шаблон master = приложение ``` Обновления шаблона выполняются через временные ветки `sync/*` по инструкции [Обычное обновление шаблона](../workflows/update-template.md). --- --- url: /template-sync-strategy/setup/existing-master-migration.md description: >- Как одноразово связать master приложения с историей шаблона, если проект был создан отдельно. --- # Миграция существующего master Этот сценарий нужен, если в репозитории приложения уже есть `master`, но он был создан не от шаблона. ## Проблема Если `master` приложения и `template` имеют разные корневые коммиты, Git видит две несвязанные истории. Плохое состояние: ```text template: T1---T2---T3 master: A1---A2 ``` При попытке выполнить обычный merge Git может ответить: ```text fatal: отказ слияния несвязанных историй изменений ``` Это означает, что у веток нет общего предка. ## Цель миграции Нужно один раз связать истории, чтобы дальше обновления шаблона шли обычным merge-процессом. После миграции история будет выглядеть примерно так: ```text template: T1---T2---T3 \ master: A1---A2-----M ``` Где `M` — одноразовый merge-коммит, который связал историю приложения с историей шаблона. ## Подключить репозиторий шаблона В репозитории приложения: ```bash cd /path/to/app-repo git remote add templates git fetch templates git fetch origin ``` Если remote `templates` уже существует: ```bash git fetch templates git fetch origin ``` ## Создать или обновить template Если ветки `template` ещё нет: ```bash git switch -c template templates/master git push -u origin template ``` Если ветка `template` уже есть: ```bash git switch template git merge --ff-only templates/master git push origin template ``` Опционально настройте удобное поведение `pull` и `push`: ```bash git config branch.template.remote templates git config branch.template.merge refs/heads/master git config branch.template.pushRemote origin git remote set-url --push templates DISABLED ``` ## Связать master с template Создайте временную ветку от текущего приложения: ```bash git fetch origin git switch -c sync/bootstrap-template origin/master ``` Слейте шаблон с разрешением несвязанных историй: ```bash git merge --allow-unrelated-histories origin/template ``` Если есть конфликты, решите их в ветке `sync/bootstrap-template`: ```bash git add . git commit ``` Если конфликтов не было, Git сам создаст merge-коммит. Запушьте ветку: ```bash git push -u origin sync/bootstrap-template ``` Дальше через UI или локально смержите: ```text sync/bootstrap-template -> master ``` ## Что проверить перед merge Посмотрите граф истории: ```bash git --no-pager log --oneline --graph --decorate --all --max-count=50 ``` Убедитесь, что `sync/bootstrap-template` содержит и историю приложения, и историю шаблона. Посмотрите итоговый diff: ```bash git --no-pager diff origin/master...sync/bootstrap-template ``` ## Когда миграцию делать не стоит Не стоит связывать истории, если приложение только что создано и его можно безопасно пересоздать от шаблона. Для нового проекта лучше сделать чистый старт по инструкции [Новый проект от шаблона](./clean-repository.md). --- --- url: /template-sync-strategy/workflows/update-template.md description: >- Повторяемый процесс доставки изменений шаблона в приложение после первичной настройки. --- # Обычное обновление шаблона Эта инструкция подходит после любого стартового сценария: * [Новый проект от шаблона](../setup/clean-repository.md). * [Миграция существующего master](../setup/existing-master-migration.md). Целевой маршрут: ```text templates/master -> template -> sync/* -> master ``` ## 1. Обновить слепок шаблона В репозитории приложения: ```bash cd /path/to/app-repo git switch template git pull --ff-only git push ``` Этот вариант работает, если для ветки `template` настроено: ```text pull из templates/master push в origin/template ``` Явная форма без зависимости от tracking-настроек: ```bash git fetch templates git switch template git merge --ff-only templates/master git push origin template ``` Если `--ff-only` падает, значит `template` перестал быть чистым слепком шаблона. Остановитесь и разберите причину до продолжения. Проверьте, что `origin/template` обновился до шаблона: ```bash git fetch origin git fetch templates git --no-pager log --oneline -1 origin/template git --no-pager log --oneline -1 templates/master ``` Оба коммита должны совпадать. ## 2. Создать ветку обновления приложения После обновления `template` создайте временную ветку от текущего приложения: ```bash git fetch origin git switch -c sync/update-template-v2 origin/master git merge origin/template ``` Имя ветки можно менять под версию или дату: ```text sync/update-template-v2 sync/update-template-2026-05-09 sync/update-template-1.8.0 ``` Проверьте, что временная ветка реально отличается от `origin/master` изменениями шаблона: ```bash git --no-pager diff --stat origin/master...HEAD ``` Если diff пустой, значит обновлённый `origin/template` не был влит в `sync/*` ветку или в шаблоне нет новых изменений. ## 3. Решить конфликты Если есть конфликты, решайте их именно в `sync/*`. После решения конфликтов: ```bash git add . git commit ``` Если конфликтов не было, Git сам создаст merge-коммит или выполнит fast-forward, в зависимости от истории. ## 4. Запушить sync-ветку ```bash git push -u origin sync/update-template-v2 ``` Дальше откройте PR/MR: ```text source: sync/update-template-v2 target: master ``` Правила merge описаны в [Review и merge](./review-and-merge.md). --- --- url: /template-sync-strategy/workflows/resolve-conflicts.md description: Почему конфликты при обновлении шаблона должны решаться только в sync-ветках. --- # Решение конфликтов Конфликт при обновлении шаблона — нормальная ситуация. Важно не то, что конфликт возник, а где он возник. Правильное место для конфликтов — временная ветка `sync/*`. ## Пример Шаблон поменял строку в `README.md`: ```text Base template version: template-conflict-v10 ``` Приложение поменяло ту же строку иначе: ```text Base template version: application-conflict-v10 ``` При merge `origin/template` в `sync/update-template-v10` появится конфликт: ```text <<<<<<< HEAD Base template version: application-conflict-v10 ======= Base template version: template-conflict-v10 >>>>>>> origin/template ``` Это правильное место конфликта: `master` ещё не изменён, `template` остаётся чистой, а итоговое решение можно проверить в PR/MR. ## Как решать 1. Оставайтесь в ветке `sync/*`. 2. Разберите конфликт по смыслу: что должно остаться в приложении после обновления шаблона. 3. Удалите conflict markers. 4. Проверьте проект локально. 5. Закоммитьте результат. ```bash git status git add . git commit ``` ## Что нельзя делать Нельзя переносить conflict resolve в `template`. `template` должна совпадать с шаблоном. Если решение конфликта попадёт туда, она перестанет быть эталоном и дальнейшие обновления станут менее предсказуемыми. Нельзя решать конфликт прямо в `master`, потому что основная ветка приложения должна получать только проверенный результат через PR/MR. ## Что проверить после resolve Посмотрите статус: ```bash git status ``` Посмотрите diff относительно текущего приложения: ```bash git --no-pager diff origin/master...HEAD ``` Посмотрите граф: ```bash git --no-pager log --oneline --graph --decorate --all --max-count=50 ``` --- --- url: /template-sync-strategy/workflows/review-and-merge.md description: Как проверять и вливать sync-ветку с обновлением шаблона в master приложения. --- # Review и merge После подготовки `sync/*` ветки обновление шаблона должно попасть в `master` через PR/MR. ## Создать PR/MR Параметры: ```text source: sync/update-template-vX target: master ``` Цель review — увидеть: * какие изменения пришли из шаблона; * какие конфликтные решения были сделаны в `sync/*`; * не попали ли в обновление лишние изменения приложения; * проходят ли проверки проекта. ## Настройки merge Для sync-PR/MR важно: ```text squash = off fast-forward merge = хорошо merge commit = допустимо squash merge = нельзя ``` Squash нельзя использовать, потому что он может уничтожить связь истории `master` с историей `template`. Особенно это критично после миграционного `sync/bootstrap-template`. ## Проверки перед merge Проверьте граф истории: ```bash git --no-pager log --oneline --graph --decorate --all --max-count=50 ``` Проверьте итоговый diff: ```bash git --no-pager diff origin/master...sync/update-template-vX ``` Проверьте проект обычными командами конкретного приложения, например: ```bash npm run lint npm run build ``` ## После merge После успешного merge в `master` можно удалить временную ветку: ```bash git branch -d sync/update-template-vX git push origin --delete sync/update-template-vX ``` Проверьте, что `master` теперь содержит обновление шаблона: ```bash git fetch origin git --no-pager log origin/template..origin/master --oneline git --no-pager diff origin/template...origin/master ``` --- --- url: /template-sync-strategy/reference/cheatsheet.md description: Короткий набор команд для регулярного обновления приложения от шаблона. --- # Памятка Рабочая схема: ```text templates/master -> template -> sync/* -> master ``` ## Обновить template В репозитории приложения: ```bash git switch template git pull --ff-only git push ``` Это подтягивает свежий шаблон из `templates/master` и пушит его в `origin/template`. ## Создать ветку обновления ```bash git fetch origin git switch -c sync/update-template-vX origin/master git merge origin/template ``` Если есть конфликты, решить их в этой же ветке: ```bash git add . git commit ``` ## Запушить sync-ветку ```bash git push -u origin sync/update-template-vX ``` ## Влить через UI Создать PR/MR: ```text source: sync/update-template-vX target: master ``` Важно: ```text squash = off ``` ## Проверка ```bash git --no-pager log --oneline --graph --decorate --all --max-count=30 ``` ## Суть процесса 1. Обновить `template` из `templates/master`. 2. Создать `sync/*` от `origin/master`. 3. Влить `origin/template` в `sync/*`. 4. Решить конфликты, если есть. 5. Запушить `sync/*`. 6. Через UI влить `sync/* -> master`. --- --- url: /template-sync-strategy/reference/troubleshooting.md description: Типовые ошибки при обновлении проекта от шаблона и способы диагностики. --- # Troubleshooting ## fatal: отказ слияния несвязанных историй изменений Ошибка: ```text fatal: отказ слияния несвязанных историй изменений ``` Причина: `master` приложения не был создан от `template`, поэтому у веток нет общего предка. Решение: выполнить одноразовую миграцию через `sync/bootstrap-template` по инструкции [Миграция существующего master](../setup/existing-master-migration.md). Коротко: ```bash git switch -c sync/bootstrap-template origin/master git merge --allow-unrelated-histories origin/template git push -u origin sync/bootstrap-template ``` ## --ff-only падает на template Ошибка возникает при команде: ```bash git merge --ff-only templates/master ``` Причина: в `template` появились коммиты, которых нет в шаблоне. Значит ветка перестала быть чистым слепком. Что проверить: ```bash git fetch templates git --no-pager log --oneline --graph --decorate templates/master..template ``` Решение зависит от причины. Не продолжайте обновление, пока не станет понятно, какие локальные коммиты попали в `template`. ## Пустой diff в sync-ветке Симптом: ```bash git --no-pager diff --stat origin/master...HEAD ``` не показывает изменений. Возможные причины: * в шаблоне нет новых изменений; * `origin/template` не был обновлён; * `origin/template` не был влит в `sync/*`; * sync-ветка создана не от актуального `origin/master`. Что проверить: ```bash git fetch origin git fetch templates git --no-pager log --oneline -1 origin/template git --no-pager log --oneline -1 templates/master git --no-pager log --oneline --graph --decorate --all --max-count=50 ``` ## Случайно включили squash Если sync-PR/MR уже влит squash-merge, история шаблона могла не сохраниться как нормальная merge-связь. Что сделать: * зафиксировать факт в описании проекта; * проверить, видит ли Git последующие обновления шаблона без повторного применения старых изменений; * при следующем обновлении внимательно смотреть diff и конфликты; * для будущих sync-PR/MR отключить squash. Если ситуация стала неуправляемой, может потребоваться отдельная техническая миграция истории. ## cannot run less Ошибка: ```text cannot run less ``` Причина: Git пытается открыть pager `less`, которого нет в системе. Решение: использовать `git --no-pager`: ```bash git --no-pager log --oneline --graph --decorate --all --max-count=50 git --no-pager diff template...master ``` --- --- url: /template-sync-strategy/reference/glossary.md description: 'Термины, которые используются в Template Sync Strategy.' --- # Глоссарий ## Template repo Репозиторий шаблона. В нём живёт общая техническая база: CI/CD, Dockerfile, зависимости, линтер, сборка, структура и документация. ## App repo Репозиторий приложения. В нём живёт продуктовый код и локальные настройки конкретного приложения. ## templates Git remote внутри репозитория приложения, который указывает на репозиторий шаблона. Пример: ```bash git remote add templates ``` ## templates/master Ветка `master` из репозитория шаблона, доступная в приложении через remote `templates`. ## template Ветка внутри репозитория приложения, которая должна быть чистым слепком `templates/master`. ## master Основная ветка приложения. Содержит шаблонную базу плюс продуктовый слой. ## sync/\* Временные ветки для обновления приложения от шаблона. Создаются от `origin/master`, получают merge из `origin/template`, проходят review и затем вливаются в `master`. ## Fast-forward Обновление ветки без merge-коммита, когда текущая ветка может быть просто передвинута вперёд по истории. ## Merge commit Коммит слияния, который сохраняет связь двух историй. Допустим для `sync/* -> master`. ## Squash Способ merge, при котором все изменения source branch превращаются в один новый коммит. Для sync-PR/MR запрещён, потому что может разрушить полезную связь истории `master` с историей `template`.