feat: добавить документацию Template Sync Strategy
- добавлены каноны и VitePress-сайт стратегии обновления шаблонов - подключена карточка документации на главной странице - добавлены сборочные скрипты, Caddy-маршрут и Docker-сборка - добавлена git-иконка для карточки и сгенерированы публичные артефакты
This commit is contained in:
@@ -21,8 +21,11 @@
|
||||
@figmaAdaptiveStandards path /figma-adaptive-standards /figma-adaptive-standards/*
|
||||
header @figmaAdaptiveStandards Link "</figma-adaptive-standards/llms.txt>; rel=\"llms\""
|
||||
|
||||
@templateSyncStrategy path /template-sync-strategy /template-sync-strategy/*
|
||||
header @templateSyncStrategy Link "</template-sync-strategy/llms.txt>; rel=\"llms\""
|
||||
|
||||
@root {
|
||||
not path /slm-design /slm-design/* /nextjs-style-guide /nextjs-style-guide/* /react-style-guide /react-style-guide/* /figma-adaptive-standards /figma-adaptive-standards/*
|
||||
not path /slm-design /slm-design/* /nextjs-style-guide /nextjs-style-guide/* /react-style-guide /react-style-guide/* /figma-adaptive-standards /figma-adaptive-standards/* /template-sync-strategy /template-sync-strategy/*
|
||||
}
|
||||
header @root Link "</llms.txt>; rel=\"llms\""
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ COPY package*.json ./
|
||||
RUN npm ci
|
||||
|
||||
COPY . .
|
||||
RUN npm run docs:build:slm-design && npm run docs:build:nextjs-style-guide && npm run docs:build:figma-adaptive-standards && npm run build
|
||||
RUN npm run docs:build:slm-design && npm run docs:build:nextjs-style-guide && npm run docs:build:figma-adaptive-standards && npm run docs:build:template-sync-strategy && npm run build
|
||||
|
||||
FROM caddy:2-alpine
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
- VitePress-сборка для `SLM Design`.
|
||||
- VitePress-сборка для `NextJS Style Guide`.
|
||||
- VitePress-сборка для `Figma Adaptive Standards`.
|
||||
- VitePress-сборка для `Template Sync Strategy`.
|
||||
- Корневой `llms.txt` как карта всех документаций.
|
||||
- Собственные `llms.txt` и `llms-full.txt` внутри каждой документации.
|
||||
- Docker/Caddy-конфигурация для публикации статической сборки.
|
||||
@@ -21,6 +22,7 @@
|
||||
- `NextJS Style Guide` — практический стайлгайд для разработки frontend-приложений на Next.js и TypeScript.
|
||||
- `React Style Guide` — будущие правила написания React-кода.
|
||||
- `Figma Adaptive Standards` — стандарты подготовки адаптивных макетов в Figma.
|
||||
- `Template Sync Strategy` — стратегия создания проектов от шаблона и долгосрочного обновления приложений через Git.
|
||||
|
||||
## Структура
|
||||
|
||||
@@ -29,6 +31,7 @@ canons/ исходные материалы и черновик
|
||||
docs/slm-design/ VitePress-сайт SLM Design
|
||||
docs/nextjs-style-guide/ VitePress-сайт NextJS Style Guide
|
||||
docs/figma-adaptive-standards/ VitePress-сайт Figma Adaptive Standards
|
||||
docs/template-sync-strategy/ VitePress-сайт Template Sync Strategy
|
||||
scripts/docs/ подготовка контента для документаций
|
||||
scripts/site/ генерация корневых артефактов сайта
|
||||
src/ React-лендинг
|
||||
@@ -46,6 +49,7 @@ npm run dev
|
||||
npm run docs:build:slm-design
|
||||
npm run docs:build:nextjs-style-guide
|
||||
npm run docs:build:figma-adaptive-standards
|
||||
npm run docs:build:template-sync-strategy
|
||||
npm run site:generate
|
||||
npm run build
|
||||
```
|
||||
@@ -56,6 +60,7 @@ npm run build
|
||||
- `npm run docs:build:slm-design` — подготавливает и собирает VitePress-документацию SLM Design.
|
||||
- `npm run docs:build:nextjs-style-guide` — подготавливает и собирает VitePress-документацию NextJS Style Guide.
|
||||
- `npm run docs:build:figma-adaptive-standards` — подготавливает и собирает VitePress-документацию Figma Adaptive Standards.
|
||||
- `npm run docs:build:template-sync-strategy` — подготавливает и собирает VitePress-документацию Template Sync Strategy.
|
||||
- `npm run site:generate` — генерирует корневой `public/llms.txt` из `src/config/docs.config.ts` и хардкод-секций.
|
||||
- `npm run build` — генерирует корневые артефакты и собирает лендинг.
|
||||
- `npm run lint` — запускает ESLint.
|
||||
@@ -79,6 +84,8 @@ npm run build
|
||||
/nextjs-style-guide/llms-full.txt
|
||||
/figma-adaptive-standards/llms.txt
|
||||
/figma-adaptive-standards/llms-full.txt
|
||||
/template-sync-strategy/llms.txt
|
||||
/template-sync-strategy/llms-full.txt
|
||||
```
|
||||
|
||||
Корневой `llms-full.txt` намеренно не создаётся. Полные bundles остаются внутри конкретных документаций.
|
||||
@@ -91,6 +98,7 @@ npm run build
|
||||
- `/nextjs-style-guide/*` → `/nextjs-style-guide/llms.txt`
|
||||
- `/react-style-guide/*` → `/react-style-guide/llms.txt`
|
||||
- `/figma-adaptive-standards/*` → `/figma-adaptive-standards/llms.txt`
|
||||
- `/template-sync-strategy/*` → `/template-sync-strategy/llms.txt`
|
||||
- остальные пути → `/llms.txt`
|
||||
|
||||
Редиректов `llms.txt` в корень нет.
|
||||
@@ -109,6 +117,7 @@ Docker-сборка выполняет:
|
||||
npm run docs:build:slm-design
|
||||
npm run docs:build:nextjs-style-guide
|
||||
npm run docs:build:figma-adaptive-standards
|
||||
npm run docs:build:template-sync-strategy
|
||||
npm run build
|
||||
```
|
||||
|
||||
|
||||
72
canons/template-sync-strategy/concepts/model.md
Normal file
72
canons/template-sync-strategy/concepts/model.md
Normal file
@@ -0,0 +1,72 @@
|
||||
---
|
||||
title: Модель веток
|
||||
description: Роли веток и remote в стратегии обновления проекта от шаблона.
|
||||
---
|
||||
|
||||
# Модель веток
|
||||
|
||||
Целевая схема:
|
||||
|
||||
```text
|
||||
templates/master -> template -> sync/* -> master
|
||||
```
|
||||
|
||||
Это логическая модель ответственности. Она не требует физически разделять файлы шаблона и приложения по папкам.
|
||||
|
||||
## templates/master
|
||||
|
||||
`templates/master` — это `master` из репозитория шаблона.
|
||||
|
||||
В репозитории приложения он доступен через remote `templates`:
|
||||
|
||||
```bash
|
||||
git remote add templates <template-repo-url>
|
||||
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.
|
||||
47
canons/template-sync-strategy/concepts/rules.md
Normal file
47
canons/template-sync-strategy/concepts/rules.md
Normal file
@@ -0,0 +1,47 @@
|
||||
---
|
||||
title: Правила процесса
|
||||
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` — эталонный слепок оригинального шаблона.
|
||||
|
||||
Если в неё попадает локальное решение конфликта или изменение приложения, она перестаёт отвечать на вопрос: “какая версия шаблона сейчас подключена к приложению?”.
|
||||
|
||||
После этого ломается главная граница ответственности: шаблон отдельно, приложение отдельно, конфликтная зона отдельно.
|
||||
44
canons/template-sync-strategy/concepts/why.md
Normal file
44
canons/template-sync-strategy/concepts/why.md
Normal file
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: Зачем это нужно
|
||||
description: Почему шаблону нужен процесс обновления, а не только быстрый старт нового проекта.
|
||||
---
|
||||
|
||||
# Зачем это нужно
|
||||
|
||||
Шаблон закрывает повторяющуюся техническую базу проекта: CI/CD, Dockerfile, зависимости, lint, build, структуру каталогов и базовую документацию.
|
||||
|
||||
Это снимает рутину на старте. Команде не нужно каждый раз заново собирать одинаковый технический каркас.
|
||||
|
||||
## Проблема после старта
|
||||
|
||||
Создать проект легко. Поддерживать 10-20 проектов сложнее.
|
||||
|
||||
Сначала проекты похожи. Потом они начинают расходиться:
|
||||
|
||||
- В одном проекте обновили CI, в другом забыли.
|
||||
- В одном проекте Dockerfile остался из шаблона, в другом его локально поправили.
|
||||
- В одном проекте зависимости уже свежие, в другом остались старые версии.
|
||||
- В одном проекте изменения шаблона перенесли руками, в другом потеряли.
|
||||
|
||||
Без процесса обновления шаблон перестаёт быть общей основой. Он остаётся только способом быстро создать первый коммит.
|
||||
|
||||
## Что ломается без стратегии
|
||||
|
||||
Когда шаблон нельзя нормально обновлять:
|
||||
|
||||
- проекты начинают жить своей жизнью;
|
||||
- граница между шаблоном и приложением теряется;
|
||||
- обновления превращаются в ручное копирование;
|
||||
- конфликты решаются прямо в рабочих ветках;
|
||||
- становится непонятно, какой проект на какой версии шаблона;
|
||||
- Git-история перестаёт быть источником правды.
|
||||
|
||||
Это особенно больно, когда приложений много. Для одного проекта ручной перенос ещё можно пережить. Для набора проектов нужен единый маршрут обновления.
|
||||
|
||||
## Цель стратегии
|
||||
|
||||
Стратегия не пытается убрать конфликты полностью. Она делает так, чтобы конфликты возникали в предсказуемом месте, проходили review и не ломали чистую ветку шаблона.
|
||||
|
||||
Главная формулировка:
|
||||
|
||||
> Шаблон должен обновляться так же контролируемо, как обычная фича: через ветку, проверку и PR/MR.
|
||||
48
canons/template-sync-strategy/index.md
Normal file
48
canons/template-sync-strategy/index.md
Normal file
@@ -0,0 +1,48 @@
|
||||
---
|
||||
title: Template Sync Strategy
|
||||
description: Управляемое обновление проектов от шаблона через чистую ветку template, временные sync-ветки и PR/MR.
|
||||
keywords: [template sync, шаблон проекта, обновление шаблона, git template, sync branch, template branch]
|
||||
---
|
||||
|
||||
# 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) — основные термины.
|
||||
75
canons/template-sync-strategy/reference/cheatsheet.md
Normal file
75
canons/template-sync-strategy/reference/cheatsheet.md
Normal file
@@ -0,0 +1,75 @@
|
||||
---
|
||||
title: Памятка
|
||||
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`.
|
||||
52
canons/template-sync-strategy/reference/glossary.md
Normal file
52
canons/template-sync-strategy/reference/glossary.md
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
title: Глоссарий
|
||||
description: Термины, которые используются в Template Sync Strategy.
|
||||
---
|
||||
|
||||
# Глоссарий
|
||||
|
||||
## Template repo
|
||||
|
||||
Репозиторий шаблона. В нём живёт общая техническая база: CI/CD, Dockerfile, зависимости, линтер, сборка, структура и документация.
|
||||
|
||||
## App repo
|
||||
|
||||
Репозиторий приложения. В нём живёт продуктовый код и локальные настройки конкретного приложения.
|
||||
|
||||
## templates
|
||||
|
||||
Git remote внутри репозитория приложения, который указывает на репозиторий шаблона.
|
||||
|
||||
Пример:
|
||||
|
||||
```bash
|
||||
git remote add templates <template-repo-url>
|
||||
```
|
||||
|
||||
## 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`.
|
||||
102
canons/template-sync-strategy/reference/troubleshooting.md
Normal file
102
canons/template-sync-strategy/reference/troubleshooting.md
Normal file
@@ -0,0 +1,102 @@
|
||||
---
|
||||
title: Troubleshooting
|
||||
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
|
||||
```
|
||||
119
canons/template-sync-strategy/setup/clean-repository.md
Normal file
119
canons/template-sync-strategy/setup/clean-repository.md
Normal file
@@ -0,0 +1,119 @@
|
||||
---
|
||||
title: Новый проект от шаблона
|
||||
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 <template-repo-url>
|
||||
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).
|
||||
144
canons/template-sync-strategy/setup/existing-master-migration.md
Normal file
144
canons/template-sync-strategy/setup/existing-master-migration.md
Normal file
@@ -0,0 +1,144 @@
|
||||
---
|
||||
title: Миграция существующего master
|
||||
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 <template-repo-url>
|
||||
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).
|
||||
78
canons/template-sync-strategy/workflows/resolve-conflicts.md
Normal file
78
canons/template-sync-strategy/workflows/resolve-conflicts.md
Normal file
@@ -0,0 +1,78 @@
|
||||
---
|
||||
title: Решение конфликтов
|
||||
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
|
||||
```
|
||||
75
canons/template-sync-strategy/workflows/review-and-merge.md
Normal file
75
canons/template-sync-strategy/workflows/review-and-merge.md
Normal file
@@ -0,0 +1,75 @@
|
||||
---
|
||||
title: Review и merge
|
||||
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
|
||||
```
|
||||
111
canons/template-sync-strategy/workflows/update-template.md
Normal file
111
canons/template-sync-strategy/workflows/update-template.md
Normal file
@@ -0,0 +1,111 @@
|
||||
---
|
||||
title: Обычное обновление шаблона
|
||||
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).
|
||||
27
docs/template-sync-strategy/.vitepress/config.ts
Normal file
27
docs/template-sync-strategy/.vitepress/config.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { defineConfig } from 'vitepress';
|
||||
import taskLists from 'markdown-it-task-lists';
|
||||
import llmstxt from 'vitepress-plugin-llms';
|
||||
import { themeSyncHead } from '../../shared/vitepress/themeHead';
|
||||
import { sidebar, site } from '../docs.config';
|
||||
|
||||
export default defineConfig({
|
||||
title: site.title,
|
||||
description: site.description,
|
||||
base: site.base,
|
||||
outDir: site.outDir,
|
||||
srcDir: 'content',
|
||||
cleanUrls: true,
|
||||
head: [...themeSyncHead],
|
||||
vite: {
|
||||
plugins: [llmstxt()],
|
||||
},
|
||||
markdown: {
|
||||
config(md) {
|
||||
md.use(taskLists);
|
||||
},
|
||||
},
|
||||
themeConfig: {
|
||||
sidebar,
|
||||
socialLinks: [],
|
||||
},
|
||||
});
|
||||
1
docs/template-sync-strategy/.vitepress/theme/index.ts
Normal file
1
docs/template-sync-strategy/.vitepress/theme/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from '../../../shared/vitepress/theme';
|
||||
64
docs/template-sync-strategy/docs.config.ts
Normal file
64
docs/template-sync-strategy/docs.config.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
export const site = {
|
||||
title: 'Template Sync Strategy',
|
||||
description: 'Управляемое обновление проектов от шаблона',
|
||||
base: '/template-sync-strategy/',
|
||||
outDir: '../../public/template-sync-strategy',
|
||||
};
|
||||
|
||||
/**
|
||||
* Карта монтирования исходных канонов в VitePress-документацию.
|
||||
*
|
||||
* `source` указывает на markdown-файл внутри `canons/`.
|
||||
* `target` задаёт путь, по которому этот файл попадёт в `docs/template-sync-strategy/content/`
|
||||
* и станет страницей итоговой документации.
|
||||
*/
|
||||
export const mounts = [
|
||||
{ target: 'index.md', source: 'template-sync-strategy/index.md' },
|
||||
{ target: 'overview.md', source: 'template-sync-strategy/index.md' },
|
||||
{ target: 'concepts/why.md', source: 'template-sync-strategy/concepts/why.md' },
|
||||
{ target: 'concepts/model.md', source: 'template-sync-strategy/concepts/model.md' },
|
||||
{ target: 'concepts/rules.md', source: 'template-sync-strategy/concepts/rules.md' },
|
||||
{ target: 'setup/clean-repository.md', source: 'template-sync-strategy/setup/clean-repository.md' },
|
||||
{ target: 'setup/existing-master-migration.md', source: 'template-sync-strategy/setup/existing-master-migration.md' },
|
||||
{ target: 'workflows/update-template.md', source: 'template-sync-strategy/workflows/update-template.md' },
|
||||
{ target: 'workflows/resolve-conflicts.md', source: 'template-sync-strategy/workflows/resolve-conflicts.md' },
|
||||
{ target: 'workflows/review-and-merge.md', source: 'template-sync-strategy/workflows/review-and-merge.md' },
|
||||
{ target: 'reference/cheatsheet.md', source: 'template-sync-strategy/reference/cheatsheet.md' },
|
||||
{ target: 'reference/troubleshooting.md', source: 'template-sync-strategy/reference/troubleshooting.md' },
|
||||
{ target: 'reference/glossary.md', source: 'template-sync-strategy/reference/glossary.md' },
|
||||
];
|
||||
|
||||
export const sidebar = [
|
||||
{
|
||||
text: 'Введение',
|
||||
items: [
|
||||
{ text: 'Обзор', link: '/overview' },
|
||||
{ text: 'Зачем это нужно', link: '/concepts/why' },
|
||||
{ text: 'Модель веток', link: '/concepts/model' },
|
||||
{ text: 'Правила процесса', link: '/concepts/rules' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Настройка',
|
||||
items: [
|
||||
{ text: 'Новый проект от шаблона', link: '/setup/clean-repository' },
|
||||
{ text: 'Миграция существующего master', link: '/setup/existing-master-migration' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Рабочие процессы',
|
||||
items: [
|
||||
{ text: 'Обычное обновление шаблона', link: '/workflows/update-template' },
|
||||
{ text: 'Решение конфликтов', link: '/workflows/resolve-conflicts' },
|
||||
{ text: 'Review и merge', link: '/workflows/review-and-merge' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Справочник',
|
||||
items: [
|
||||
{ text: 'Памятка', link: '/reference/cheatsheet' },
|
||||
{ text: 'Troubleshooting', link: '/reference/troubleshooting' },
|
||||
{ text: 'Глоссарий', link: '/reference/glossary' },
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -12,6 +12,8 @@
|
||||
"docs:build:nextjs-style-guide": "npm run docs:prepare:nextjs-style-guide && vitepress build docs/nextjs-style-guide",
|
||||
"docs:prepare:figma-adaptive-standards": "tsx scripts/docs/prepare.ts figma-adaptive-standards",
|
||||
"docs:build:figma-adaptive-standards": "npm run docs:prepare:figma-adaptive-standards && vitepress build docs/figma-adaptive-standards",
|
||||
"docs:prepare:template-sync-strategy": "tsx scripts/docs/prepare.ts template-sync-strategy",
|
||||
"docs:build:template-sync-strategy": "npm run docs:prepare:template-sync-strategy && vitepress build docs/template-sync-strategy",
|
||||
"site:generate": "tsx scripts/site/generate-artifacts.ts",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview"
|
||||
|
||||
10
public/icons/git-branch-outline.svg
Normal file
10
public/icons/git-branch-outline.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Source: https://www.svgrepo.com/show/326651/git-branch-outline.svg -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>ionicons-v5-d</title>
|
||||
<circle cx="160" cy="96" r="48" style="fill:none;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px" />
|
||||
<circle cx="160" cy="416" r="48" style="fill:none;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px" />
|
||||
<line x1="160" y1="368" x2="160" y2="144" style="fill:none;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px" />
|
||||
<circle cx="352" cy="160" r="48" style="fill:none;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px" />
|
||||
<path d="M352,208c0,128-192,48-192,160" style="fill:none;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 920 B |
23
public/template-sync-strategy/404.html
Normal file
23
public/template-sync-strategy/404.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US" dir="ltr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>404 | Template Sync Strategy</title>
|
||||
<meta name="description" content="Not Found">
|
||||
<meta name="generator" content="VitePress v1.6.4">
|
||||
<link rel="preload stylesheet" href="/template-sync-strategy/assets/style.CSIvdBoa.css" as="style">
|
||||
<link rel="preload stylesheet" href="/template-sync-strategy/vp-icons.css" as="style">
|
||||
|
||||
<script type="module" src="/template-sync-strategy/assets/app.0Bzyh7PD.js"></script>
|
||||
<link rel="preload" href="/template-sync-strategy/assets/inter-roman-latin.Di8DUHzh.woff2" as="font" type="font/woff2" crossorigin="">
|
||||
<script id="sync-docs-theme">(()=>{if(localStorage.getItem("vitepress-theme-appearance"))return;const e=localStorage.getItem("all-docs-theme");e&&(localStorage.setItem("vitepress-theme-appearance",e==="system"?"auto":e),localStorage.removeItem("all-docs-theme"))})();</script>
|
||||
<script id="check-dark-mode">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"auto",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
|
||||
<script id="check-mac-os">document.documentElement.classList.toggle("mac",/Mac|iPhone|iPod|iPad/i.test(navigator.platform));</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script>window.__VP_HASH_MAP__=JSON.parse("{\"concepts_model.md\":\"C805A9As\",\"concepts_rules.md\":\"QraT4IhZ\",\"concepts_why.md\":\"akfw90Fj\",\"index.md\":\"C5Q_ZnE3\",\"overview.md\":\"DOeHHuHO\",\"reference_cheatsheet.md\":\"0TzKSaSb\",\"reference_glossary.md\":\"DLD-b2Ke\",\"reference_troubleshooting.md\":\"BrYSpYuW\",\"setup_clean-repository.md\":\"CPqmBfph\",\"setup_existing-master-migration.md\":\"BQ5VImS9\",\"workflows_resolve-conflicts.md\":\"CujNWdsi\",\"workflows_review-and-merge.md\":\"D5KhlAbu\",\"workflows_update-template.md\":\"C8s1FFCq\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"en-US\",\"dir\":\"ltr\",\"title\":\"Template Sync Strategy\",\"description\":\"Управляемое обновление проектов от шаблона\",\"base\":\"/template-sync-strategy/\",\"head\":[],\"router\":{\"prefetchLinks\":true},\"appearance\":true,\"themeConfig\":{\"sidebar\":[{\"text\":\"Введение\",\"items\":[{\"text\":\"Обзор\",\"link\":\"/overview\"},{\"text\":\"Зачем это нужно\",\"link\":\"/concepts/why\"},{\"text\":\"Модель веток\",\"link\":\"/concepts/model\"},{\"text\":\"Правила процесса\",\"link\":\"/concepts/rules\"}]},{\"text\":\"Настройка\",\"items\":[{\"text\":\"Новый проект от шаблона\",\"link\":\"/setup/clean-repository\"},{\"text\":\"Миграция существующего master\",\"link\":\"/setup/existing-master-migration\"}]},{\"text\":\"Рабочие процессы\",\"items\":[{\"text\":\"Обычное обновление шаблона\",\"link\":\"/workflows/update-template\"},{\"text\":\"Решение конфликтов\",\"link\":\"/workflows/resolve-conflicts\"},{\"text\":\"Review и merge\",\"link\":\"/workflows/review-and-merge\"}]},{\"text\":\"Справочник\",\"items\":[{\"text\":\"Памятка\",\"link\":\"/reference/cheatsheet\"},{\"text\":\"Troubleshooting\",\"link\":\"/reference/troubleshooting\"},{\"text\":\"Глоссарий\",\"link\":\"/reference/glossary\"}]}],\"socialLinks\":[]},\"locales\":{},\"scrollOffset\":134,\"cleanUrls\":true}");</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
1
public/template-sync-strategy/assets/app.0Bzyh7PD.js
Normal file
1
public/template-sync-strategy/assets/app.0Bzyh7PD.js
Normal file
@@ -0,0 +1 @@
|
||||
import{R as p}from"./chunks/theme.CloMnL7i.js";import{R as s,a1 as i,a2 as u,a3 as c,a4 as l,a5 as f,a6 as d,a7 as m,a8 as h,a9 as g,aa as A,d as v,u as R,v as w,s as y,ab as C,ac as P,ad as b,a0 as E}from"./chunks/framework.B1nRs-GM.js";function r(e){if(e.extends){const a=r(e.extends);return{...a,...e,async enhanceApp(t){a.enhanceApp&&await a.enhanceApp(t),e.enhanceApp&&await e.enhanceApp(t)}}}return e}const n=r(p),S=v({name:"VitePressApp",setup(){const{site:e,lang:a,dir:t}=R();return w(()=>{y(()=>{document.documentElement.lang=a.value,document.documentElement.dir=t.value})}),e.value.router.prefetchLinks&&C(),P(),b(),n.setup&&n.setup(),()=>E(n.Layout)}});async function T(){globalThis.__VITEPRESS__=!0;const e=_(),a=D();a.provide(u,e);const t=c(e.route);return a.provide(l,t),a.component("Content",f),a.component("ClientOnly",d),Object.defineProperties(a.config.globalProperties,{$frontmatter:{get(){return t.frontmatter.value}},$params:{get(){return t.page.value.params}}}),n.enhanceApp&&await n.enhanceApp({app:a,router:e,siteData:m}),{app:a,router:e,data:t}}function D(){return A(S)}function _(){let e=s;return h(a=>{let t=g(a),o=null;return t&&(e&&(t=t.replace(/\.js$/,".lean.js")),o=import(t)),s&&(e=!1),o},n.NotFound)}s&&T().then(({app:e,router:a,data:t})=>{a.go().then(()=>{i(a.route,t.site),e.mount("#app")})});export{T as createApp};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
|
||||
import{_ as a,o as s,c as t,ae as i}from"./chunks/framework.B1nRs-GM.js";const k=JSON.parse('{"title":"Модель веток","description":"Роли веток и remote в стратегии обновления проекта от шаблона.","frontmatter":{"title":"Модель веток","description":"Роли веток и remote в стратегии обновления проекта от шаблона."},"headers":[],"relativePath":"concepts/model.md","filePath":"concepts/model.md"}'),p={name:"concepts/model.md"};function l(n,e,d,o,h,r){return s(),t("div",null,[...e[0]||(e[0]=[i(`<div style="display:none;" hidden="true" aria-hidden="true">Are you an LLM? You can read better optimized documentation at /template-sync-strategy/concepts/model.md for this page in Markdown format</div><h1 id="модель-веток" tabindex="-1">Модель веток <a class="header-anchor" href="#модель-веток" aria-label="Permalink to "Модель веток""></a></h1><p>Целевая схема:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>templates/master -> template -> sync/* -> master</span></span></code></pre></div><p>Это логическая модель ответственности. Она не требует физически разделять файлы шаблона и приложения по папкам.</p><h2 id="templates-master" tabindex="-1">templates/master <a class="header-anchor" href="#templates-master" aria-label="Permalink to "templates/master""></a></h2><p><code>templates/master</code> — это <code>master</code> из репозитория шаблона.</p><p>В репозитории приложения он доступен через remote <code>templates</code>:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> remote</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> add</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> templates</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> <</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">template-repo-ur</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">l</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">></span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> fetch</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> templates</span></span></code></pre></div><p>Этот remote считается источником обновлений шаблона.</p><h2 id="template" tabindex="-1">template <a class="header-anchor" href="#template" aria-label="Permalink to "template""></a></h2><p><code>template</code> — чистый слепок шаблона внутри репозитория приложения.</p><p>Его задача — показать, какая версия шаблонной базы сейчас доступна приложению.</p><p>В <code>template</code> нельзя коммитить руками изменения приложения. Эта ветка обновляется только из <code>templates/master</code>.</p><h2 id="master" tabindex="-1">master <a class="header-anchor" href="#master" aria-label="Permalink to "master""></a></h2><p><code>master</code> — основная ветка приложения.</p><p>Она содержит:</p><ul><li>базу шаблона;</li><li>продуктовый код;</li><li>локальные настройки приложения;</li><li>историю применения обновлений шаблона.</li></ul><p><code>master</code> не используется как место ручного решения конфликтов при обновлении шаблона.</p><h2 id="sync" tabindex="-1">sync/* <a class="header-anchor" href="#sync" aria-label="Permalink to "sync/*""></a></h2><p><code>sync/*</code> — временная ветка для обновления приложения от шаблона.</p><p>Она создаётся от актуального <code>origin/master</code>, после чего в неё вливается <code>origin/template</code>.</p><p>Пример:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> fetch</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> switch</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -c</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> sync/update-template-v2</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin/master</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> merge</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin/template</span></span></code></pre></div><p>Если появляются конфликты, они решаются именно в этой ветке.</p><h2 id="почему-нужен-отдельныи-sync-слои" tabindex="-1">Почему нужен отдельный sync-слой <a class="header-anchor" href="#почему-нужен-отдельныи-sync-слои" aria-label="Permalink to "Почему нужен отдельный sync-слой""></a></h2><p>Нельзя безопасно использовать <code>template</code> как source branch для прямого PR/MR в <code>master</code>: если возникнет конфликт, решение может попасть в <code>template</code>.</p><p>После этого <code>template</code> перестанет быть чистым слепком шаблона. Git начнёт видеть в ней не только шаблон, но и локальные решения конкретного приложения.</p><p><code>sync/*</code> можно пачкать conflict resolve-коммитами, проверками и правками совместимости. Эта ветка временная и удаляется после merge.</p>`,29)])])}const m=a(p,[["render",l]]);export{k as __pageData,m as default};
|
||||
@@ -0,0 +1 @@
|
||||
import{_ as a,o as s,c as t,ae as i}from"./chunks/framework.B1nRs-GM.js";const k=JSON.parse('{"title":"Модель веток","description":"Роли веток и remote в стратегии обновления проекта от шаблона.","frontmatter":{"title":"Модель веток","description":"Роли веток и remote в стратегии обновления проекта от шаблона."},"headers":[],"relativePath":"concepts/model.md","filePath":"concepts/model.md"}'),p={name:"concepts/model.md"};function l(n,e,d,o,h,r){return s(),t("div",null,[...e[0]||(e[0]=[i("",29)])])}const m=a(p,[["render",l]]);export{k as __pageData,m as default};
|
||||
@@ -0,0 +1,3 @@
|
||||
import{_ as a,o as t,c as s,ae as o}from"./chunks/framework.B1nRs-GM.js";const h=JSON.parse('{"title":"Правила процесса","description":"Набор правил, который удерживает template чистой, а обновления шаблона контролируемыми.","frontmatter":{"title":"Правила процесса","description":"Набор правил, который удерживает template чистой, а обновления шаблона контролируемыми."},"headers":[],"relativePath":"concepts/rules.md","filePath":"concepts/rules.md"}'),l={name:"concepts/rules.md"};function c(i,e,d,n,r,p){return t(),s("div",null,[...e[0]||(e[0]=[o(`<div style="display:none;" hidden="true" aria-hidden="true">Are you an LLM? You can read better optimized documentation at /template-sync-strategy/concepts/rules.md for this page in Markdown format</div><h1 id="правила-процесса" tabindex="-1">Правила процесса <a class="header-anchor" href="#правила-процесса" aria-label="Permalink to "Правила процесса""></a></h1><p>Небольшой набор правил удерживает схему чистой.</p><h2 id="делаем" tabindex="-1">Делаем <a class="header-anchor" href="#делаем" aria-label="Permalink to "Делаем""></a></h2><ul><li><code>template</code> обновляем только из <code>templates/master</code>.</li><li><code>sync/*</code> создаём от <code>origin/master</code>.</li><li><code>origin/template</code> вливаем в <code>sync/*</code>, а не напрямую в <code>master</code>.</li><li>Конфликты решаем только в <code>sync/*</code>.</li><li><code>sync/* -> master</code> вливаем через PR/MR.</li><li>Для sync-PR/MR отключаем squash.</li></ul><h2 id="не-делаем" tabindex="-1">Не делаем <a class="header-anchor" href="#не-делаем" aria-label="Permalink to "Не делаем""></a></h2><ul><li>Не правим <code>template</code> руками.</li><li>Не коммитим изменения приложения в <code>template</code>.</li><li>Не мержим <code>template -> master</code> напрямую.</li><li>Не решаем конфликты в <code>master</code>.</li><li>Не включаем squash для <code>sync/* -> master</code>.</li></ul><h2 id="почему-squash-нельзя" tabindex="-1">Почему squash нельзя <a class="header-anchor" href="#почему-squash-нельзя" aria-label="Permalink to "Почему squash нельзя""></a></h2><p>Squash может уничтожить нормальную связь истории <code>master</code> с историей <code>template</code>.</p><p>Git использует историю, чтобы понимать, какие изменения шаблона уже были доставлены в приложение. Если результат обновления шаблона превратить в один squash-коммит, связь с исходными коммитами шаблона станет хуже или исчезнет.</p><p>Для sync-PR/MR допустимы:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>fast-forward merge = хорошо</span></span>
|
||||
<span class="line"><span>merge commit = допустимо</span></span>
|
||||
<span class="line"><span>squash merge = нельзя</span></span></code></pre></div><h2 id="почему-template-нельзя-пачкать" tabindex="-1">Почему template нельзя пачкать <a class="header-anchor" href="#почему-template-нельзя-пачкать" aria-label="Permalink to "Почему template нельзя пачкать""></a></h2><p><code>template</code> — эталонный слепок оригинального шаблона.</p><p>Если в неё попадает локальное решение конфликта или изменение приложения, она перестаёт отвечать на вопрос: “какая версия шаблона сейчас подключена к приложению?”.</p><p>После этого ломается главная граница ответственности: шаблон отдельно, приложение отдельно, конфликтная зона отдельно.</p>`,16)])])}const u=a(l,[["render",c]]);export{h as __pageData,u as default};
|
||||
@@ -0,0 +1 @@
|
||||
import{_ as a,o as t,c as s,ae as o}from"./chunks/framework.B1nRs-GM.js";const h=JSON.parse('{"title":"Правила процесса","description":"Набор правил, который удерживает template чистой, а обновления шаблона контролируемыми.","frontmatter":{"title":"Правила процесса","description":"Набор правил, который удерживает template чистой, а обновления шаблона контролируемыми."},"headers":[],"relativePath":"concepts/rules.md","filePath":"concepts/rules.md"}'),l={name:"concepts/rules.md"};function c(i,e,d,n,r,p){return t(),s("div",null,[...e[0]||(e[0]=[o("",16)])])}const u=a(l,[["render",c]]);export{h as __pageData,u as default};
|
||||
@@ -0,0 +1 @@
|
||||
import{_ as a,o as t,c as i,ae as l}from"./chunks/framework.B1nRs-GM.js";const u=JSON.parse('{"title":"Зачем это нужно","description":"Почему шаблону нужен процесс обновления, а не только быстрый старт нового проекта.","frontmatter":{"title":"Зачем это нужно","description":"Почему шаблону нужен процесс обновления, а не только быстрый старт нового проекта."},"headers":[],"relativePath":"concepts/why.md","filePath":"concepts/why.md"}'),o={name:"concepts/why.md"};function r(n,e,p,c,d,s){return t(),i("div",null,[...e[0]||(e[0]=[l('<div style="display:none;" hidden="true" aria-hidden="true">Are you an LLM? You can read better optimized documentation at /template-sync-strategy/concepts/why.md for this page in Markdown format</div><h1 id="зачем-это-нужно" tabindex="-1">Зачем это нужно <a class="header-anchor" href="#зачем-это-нужно" aria-label="Permalink to "Зачем это нужно""></a></h1><p>Шаблон закрывает повторяющуюся техническую базу проекта: CI/CD, Dockerfile, зависимости, lint, build, структуру каталогов и базовую документацию.</p><p>Это снимает рутину на старте. Команде не нужно каждый раз заново собирать одинаковый технический каркас.</p><h2 id="проблема-после-старта" tabindex="-1">Проблема после старта <a class="header-anchor" href="#проблема-после-старта" aria-label="Permalink to "Проблема после старта""></a></h2><p>Создать проект легко. Поддерживать 10-20 проектов сложнее.</p><p>Сначала проекты похожи. Потом они начинают расходиться:</p><ul><li>В одном проекте обновили CI, в другом забыли.</li><li>В одном проекте Dockerfile остался из шаблона, в другом его локально поправили.</li><li>В одном проекте зависимости уже свежие, в другом остались старые версии.</li><li>В одном проекте изменения шаблона перенесли руками, в другом потеряли.</li></ul><p>Без процесса обновления шаблон перестаёт быть общей основой. Он остаётся только способом быстро создать первый коммит.</p><h2 id="что-ломается-без-стратегии" tabindex="-1">Что ломается без стратегии <a class="header-anchor" href="#что-ломается-без-стратегии" aria-label="Permalink to "Что ломается без стратегии""></a></h2><p>Когда шаблон нельзя нормально обновлять:</p><ul><li>проекты начинают жить своей жизнью;</li><li>граница между шаблоном и приложением теряется;</li><li>обновления превращаются в ручное копирование;</li><li>конфликты решаются прямо в рабочих ветках;</li><li>становится непонятно, какой проект на какой версии шаблона;</li><li>Git-история перестаёт быть источником правды.</li></ul><p>Это особенно больно, когда приложений много. Для одного проекта ручной перенос ещё можно пережить. Для набора проектов нужен единый маршрут обновления.</p><h2 id="цель-стратегии" tabindex="-1">Цель стратегии <a class="header-anchor" href="#цель-стратегии" aria-label="Permalink to "Цель стратегии""></a></h2><p>Стратегия не пытается убрать конфликты полностью. Она делает так, чтобы конфликты возникали в предсказуемом месте, проходили review и не ломали чистую ветку шаблона.</p><p>Главная формулировка:</p><blockquote><p>Шаблон должен обновляться так же контролируемо, как обычная фича: через ветку, проверку и PR/MR.</p></blockquote>',17)])])}const _=a(o,[["render",r]]);export{u as __pageData,_ as default};
|
||||
@@ -0,0 +1 @@
|
||||
import{_ as a,o as t,c as i,ae as l}from"./chunks/framework.B1nRs-GM.js";const u=JSON.parse('{"title":"Зачем это нужно","description":"Почему шаблону нужен процесс обновления, а не только быстрый старт нового проекта.","frontmatter":{"title":"Зачем это нужно","description":"Почему шаблону нужен процесс обновления, а не только быстрый старт нового проекта."},"headers":[],"relativePath":"concepts/why.md","filePath":"concepts/why.md"}'),o={name:"concepts/why.md"};function r(n,e,p,c,d,s){return t(),i("div",null,[...e[0]||(e[0]=[l("",17)])])}const _=a(o,[["render",r]]);export{u as __pageData,_ as default};
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
import{_ as t,o as a,c as l,ae as r}from"./chunks/framework.B1nRs-GM.js";const h=JSON.parse('{"title":"Template Sync Strategy","description":"Управляемое обновление проектов от шаблона через чистую ветку template, временные sync-ветки и PR/MR.","frontmatter":{"title":"Template Sync Strategy","description":"Управляемое обновление проектов от шаблона через чистую ветку template, временные sync-ветки и PR/MR.","keywords":["template sync","шаблон проекта","обновление шаблона","git template","sync branch","template branch"]},"headers":[],"relativePath":"index.md","filePath":"index.md"}'),o={name:"index.md"};function i(s,e,c,n,d,p){return a(),l("div",null,[...e[0]||(e[0]=[r("",15)])])}const u=t(o,[["render",i]]);export{h as __pageData,u as default};
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
import{_ as a,o as t,c as r,ae as l}from"./chunks/framework.B1nRs-GM.js";const h=JSON.parse('{"title":"Template Sync Strategy","description":"Управляемое обновление проектов от шаблона через чистую ветку template, временные sync-ветки и PR/MR.","frontmatter":{"title":"Template Sync Strategy","description":"Управляемое обновление проектов от шаблона через чистую ветку template, временные sync-ветки и PR/MR.","keywords":["template sync","шаблон проекта","обновление шаблона","git template","sync branch","template branch"]},"headers":[],"relativePath":"overview.md","filePath":"overview.md"}'),o={name:"overview.md"};function i(s,e,c,n,d,p){return t(),r("div",null,[...e[0]||(e[0]=[l("",15)])])}const f=a(o,[["render",i]]);export{h as __pageData,f as default};
|
||||
@@ -0,0 +1,7 @@
|
||||
import{_ as a,o as i,c as e,ae as t}from"./chunks/framework.B1nRs-GM.js";const k=JSON.parse('{"title":"Памятка","description":"Короткий набор команд для регулярного обновления приложения от шаблона.","frontmatter":{"title":"Памятка","description":"Короткий набор команд для регулярного обновления приложения от шаблона."},"headers":[],"relativePath":"reference/cheatsheet.md","filePath":"reference/cheatsheet.md"}'),n={name:"reference/cheatsheet.md"};function l(h,s,p,d,c,o){return i(),e("div",null,[...s[0]||(s[0]=[t(`<div style="display:none;" hidden="true" aria-hidden="true">Are you an LLM? You can read better optimized documentation at /template-sync-strategy/reference/cheatsheet.md for this page in Markdown format</div><h1 id="памятка" tabindex="-1">Памятка <a class="header-anchor" href="#памятка" aria-label="Permalink to "Памятка""></a></h1><p>Рабочая схема:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>templates/master -> template -> sync/* -> master</span></span></code></pre></div><h2 id="обновить-template" tabindex="-1">Обновить template <a class="header-anchor" href="#обновить-template" aria-label="Permalink to "Обновить template""></a></h2><p>В репозитории приложения:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> switch</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> template</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> pull</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --ff-only</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> push</span></span></code></pre></div><p>Это подтягивает свежий шаблон из <code>templates/master</code> и пушит его в <code>origin/template</code>.</p><h2 id="создать-ветку-обновления" tabindex="-1">Создать ветку обновления <a class="header-anchor" href="#создать-ветку-обновления" aria-label="Permalink to "Создать ветку обновления""></a></h2><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> fetch</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> switch</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -c</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> sync/update-template-vX</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin/master</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> merge</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin/template</span></span></code></pre></div><p>Если есть конфликты, решить их в этой же ветке:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> add</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> commit</span></span></code></pre></div><h2 id="запушить-sync-ветку" tabindex="-1">Запушить sync-ветку <a class="header-anchor" href="#запушить-sync-ветку" aria-label="Permalink to "Запушить sync-ветку""></a></h2><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> push</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -u</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> sync/update-template-vX</span></span></code></pre></div><h2 id="влить-через-ui" tabindex="-1">Влить через UI <a class="header-anchor" href="#влить-через-ui" aria-label="Permalink to "Влить через UI""></a></h2><p>Создать PR/MR:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>source: sync/update-template-vX</span></span>
|
||||
<span class="line"><span>target: master</span></span></code></pre></div><p>Важно:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>squash = off</span></span></code></pre></div><h2 id="проверка" tabindex="-1">Проверка <a class="header-anchor" href="#проверка" aria-label="Permalink to "Проверка""></a></h2><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --no-pager</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> log</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --oneline</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --graph</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --decorate</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --all</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --max-count=30</span></span></code></pre></div><h2 id="суть-процесса" tabindex="-1">Суть процесса <a class="header-anchor" href="#суть-процесса" aria-label="Permalink to "Суть процесса""></a></h2><ol><li>Обновить <code>template</code> из <code>templates/master</code>.</li><li>Создать <code>sync/*</code> от <code>origin/master</code>.</li><li>Влить <code>origin/template</code> в <code>sync/*</code>.</li><li>Решить конфликты, если есть.</li><li>Запушить <code>sync/*</code>.</li><li>Через UI влить <code>sync/* -> master</code>.</li></ol>`,23)])])}const g=a(n,[["render",l]]);export{k as __pageData,g as default};
|
||||
@@ -0,0 +1 @@
|
||||
import{_ as a,o as i,c as e,ae as t}from"./chunks/framework.B1nRs-GM.js";const k=JSON.parse('{"title":"Памятка","description":"Короткий набор команд для регулярного обновления приложения от шаблона.","frontmatter":{"title":"Памятка","description":"Короткий набор команд для регулярного обновления приложения от шаблона."},"headers":[],"relativePath":"reference/cheatsheet.md","filePath":"reference/cheatsheet.md"}'),n={name:"reference/cheatsheet.md"};function l(h,s,p,d,c,o){return i(),e("div",null,[...s[0]||(s[0]=[t("",23)])])}const g=a(n,[["render",l]]);export{k as __pageData,g as default};
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
import{_ as a,o as t,c as r,ae as s}from"./chunks/framework.B1nRs-GM.js";const m=JSON.parse('{"title":"Глоссарий","description":"Термины, которые используются в Template Sync Strategy.","frontmatter":{"title":"Глоссарий","description":"Термины, которые используются в Template Sync Strategy."},"headers":[],"relativePath":"reference/glossary.md","filePath":"reference/glossary.md"}'),i={name:"reference/glossary.md"};function o(l,e,p,n,d,h){return t(),r("div",null,[...e[0]||(e[0]=[s("",24)])])}const u=a(i,[["render",o]]);export{m as __pageData,u as default};
|
||||
@@ -0,0 +1,9 @@
|
||||
import{_ as i,o as a,c as t,ae as e}from"./chunks/framework.B1nRs-GM.js";const g=JSON.parse('{"title":"Troubleshooting","description":"Типовые ошибки при обновлении проекта от шаблона и способы диагностики.","frontmatter":{"title":"Troubleshooting","description":"Типовые ошибки при обновлении проекта от шаблона и способы диагностики."},"headers":[],"relativePath":"reference/troubleshooting.md","filePath":"reference/troubleshooting.md"}'),n={name:"reference/troubleshooting.md"};function l(h,s,p,k,r,o){return a(),t("div",null,[...s[0]||(s[0]=[e(`<div style="display:none;" hidden="true" aria-hidden="true">Are you an LLM? You can read better optimized documentation at /template-sync-strategy/reference/troubleshooting.md for this page in Markdown format</div><h1 id="troubleshooting" tabindex="-1">Troubleshooting <a class="header-anchor" href="#troubleshooting" aria-label="Permalink to "Troubleshooting""></a></h1><h2 id="fatal-отказ-слияния-несвязанных-истории-изменении" tabindex="-1">fatal: отказ слияния несвязанных историй изменений <a class="header-anchor" href="#fatal-отказ-слияния-несвязанных-истории-изменении" aria-label="Permalink to "fatal: отказ слияния несвязанных историй изменений""></a></h2><p>Ошибка:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>fatal: отказ слияния несвязанных историй изменений</span></span></code></pre></div><p>Причина: <code>master</code> приложения не был создан от <code>template</code>, поэтому у веток нет общего предка.</p><p>Решение: выполнить одноразовую миграцию через <code>sync/bootstrap-template</code> по инструкции <a href="./../setup/existing-master-migration">Миграция существующего master</a>.</p><p>Коротко:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> switch</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -c</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> sync/bootstrap-template</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin/master</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> merge</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --allow-unrelated-histories</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin/template</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> push</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -u</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> sync/bootstrap-template</span></span></code></pre></div><h2 id="ff-only-падает-на-template" tabindex="-1">--ff-only падает на template <a class="header-anchor" href="#ff-only-падает-на-template" aria-label="Permalink to "--ff-only падает на template""></a></h2><p>Ошибка возникает при команде:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> merge</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --ff-only</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> templates/master</span></span></code></pre></div><p>Причина: в <code>template</code> появились коммиты, которых нет в шаблоне. Значит ветка перестала быть чистым слепком.</p><p>Что проверить:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> fetch</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> templates</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --no-pager</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> log</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --oneline</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --graph</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --decorate</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> templates/master..template</span></span></code></pre></div><p>Решение зависит от причины. Не продолжайте обновление, пока не станет понятно, какие локальные коммиты попали в <code>template</code>.</p><h2 id="пустои-diff-в-sync-ветке" tabindex="-1">Пустой diff в sync-ветке <a class="header-anchor" href="#пустои-diff-в-sync-ветке" aria-label="Permalink to "Пустой diff в sync-ветке""></a></h2><p>Симптом:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --no-pager</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> diff</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --stat</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin/master...HEAD</span></span></code></pre></div><p>не показывает изменений.</p><p>Возможные причины:</p><ul><li>в шаблоне нет новых изменений;</li><li><code>origin/template</code> не был обновлён;</li><li><code>origin/template</code> не был влит в <code>sync/*</code>;</li><li>sync-ветка создана не от актуального <code>origin/master</code>.</li></ul><p>Что проверить:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> fetch</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> fetch</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> templates</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --no-pager</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> log</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --oneline</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -1</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin/template</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --no-pager</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> log</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --oneline</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -1</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> templates/master</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --no-pager</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> log</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --oneline</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --graph</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --decorate</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --all</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --max-count=50</span></span></code></pre></div><h2 id="случаино-включили-squash" tabindex="-1">Случайно включили squash <a class="header-anchor" href="#случаино-включили-squash" aria-label="Permalink to "Случайно включили squash""></a></h2><p>Если sync-PR/MR уже влит squash-merge, история шаблона могла не сохраниться как нормальная merge-связь.</p><p>Что сделать:</p><ul><li>зафиксировать факт в описании проекта;</li><li>проверить, видит ли Git последующие обновления шаблона без повторного применения старых изменений;</li><li>при следующем обновлении внимательно смотреть diff и конфликты;</li><li>для будущих sync-PR/MR отключить squash.</li></ul><p>Если ситуация стала неуправляемой, может потребоваться отдельная техническая миграция истории.</p><h2 id="cannot-run-less" tabindex="-1">cannot run less <a class="header-anchor" href="#cannot-run-less" aria-label="Permalink to "cannot run less""></a></h2><p>Ошибка:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>cannot run less</span></span></code></pre></div><p>Причина: Git пытается открыть pager <code>less</code>, которого нет в системе.</p><p>Решение: использовать <code>git --no-pager</code>:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --no-pager</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> log</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --oneline</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --graph</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --decorate</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --all</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --max-count=50</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --no-pager</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> diff</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> template...master</span></span></code></pre></div>`,35)])])}const F=i(n,[["render",l]]);export{g as __pageData,F as default};
|
||||
@@ -0,0 +1 @@
|
||||
import{_ as i,o as a,c as t,ae as e}from"./chunks/framework.B1nRs-GM.js";const g=JSON.parse('{"title":"Troubleshooting","description":"Типовые ошибки при обновлении проекта от шаблона и способы диагностики.","frontmatter":{"title":"Troubleshooting","description":"Типовые ошибки при обновлении проекта от шаблона и способы диагностики."},"headers":[],"relativePath":"reference/troubleshooting.md","filePath":"reference/troubleshooting.md"}'),n={name:"reference/troubleshooting.md"};function l(h,s,p,k,r,o){return a(),t("div",null,[...s[0]||(s[0]=[e("",35)])])}const F=i(n,[["render",l]]);export{g as __pageData,F as default};
|
||||
@@ -0,0 +1,18 @@
|
||||
import{_ as a,o as i,c as t,ae as e}from"./chunks/framework.B1nRs-GM.js";const F=JSON.parse('{"title":"Новый проект от шаблона","description":"Старт нового приложения от шаблонного репозитория с правильной историей веток.","frontmatter":{"title":"Новый проект от шаблона","description":"Старт нового приложения от шаблонного репозитория с правильной историей веток."},"headers":[],"relativePath":"setup/clean-repository.md","filePath":"setup/clean-repository.md"}'),p={name:"setup/clean-repository.md"};function n(l,s,h,k,d,r){return i(),t("div",null,[...s[0]||(s[0]=[e(`<div style="display:none;" hidden="true" aria-hidden="true">Are you an LLM? You can read better optimized documentation at /template-sync-strategy/setup/clean-repository.md for this page in Markdown format</div><h1 id="новыи-проект-от-шаблона" tabindex="-1">Новый проект от шаблона <a class="header-anchor" href="#новыи-проект-от-шаблона" aria-label="Permalink to "Новый проект от шаблона""></a></h1><p>Этот сценарий подходит, когда репозиторий приложения ещё пустой или его можно безопасно пересоздать от шаблона.</p><p>Целевая модель:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>templates/master -> template -> sync/* -> master</span></span></code></pre></div><h2 id="условия" tabindex="-1">Условия <a class="header-anchor" href="#условия" aria-label="Permalink to "Условия""></a></h2><p>Есть два репозитория:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>template repo = репозиторий шаблона</span></span>
|
||||
<span class="line"><span>app repo = репозиторий приложения</span></span></code></pre></div><p>В обоих репозиториях основная ветка называется <code>master</code>.</p><h2 id="подготовить-шаблон" tabindex="-1">Подготовить шаблон <a class="header-anchor" href="#подготовить-шаблон" aria-label="Permalink to "Подготовить шаблон""></a></h2><p>В репозитории шаблона:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">cd</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> /path/to/template-repo</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> switch</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> master</span></span></code></pre></div><p>Если это пустой репозиторий, добавьте первый файл и запушьте <code>master</code>:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">printf</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "# Template Repository\\n\\nBase template version: v1\\n"</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> ></span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> README.md</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> add</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> README.md</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> commit</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -m</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "docs: добавить базовый шаблон"</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> push</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -u</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> master</span></span></code></pre></div><h2 id="подключить-шаблон-в-приложении" tabindex="-1">Подключить шаблон в приложении <a class="header-anchor" href="#подключить-шаблон-в-приложении" aria-label="Permalink to "Подключить шаблон в приложении""></a></h2><p>В репозитории приложения:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">cd</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> /path/to/app-repo</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> remote</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> add</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> templates</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> <</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">template-repo-ur</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">l</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">></span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> fetch</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> templates</span></span></code></pre></div><p>Создайте ветку <code>template</code> от шаблона:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> switch</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -c</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> template</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> templates/master</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> push</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -u</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> template</span></span></code></pre></div><p>Создайте ветку приложения <code>master</code> от <code>template</code>:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> switch</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -c</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> master</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> template</span></span></code></pre></div><p>Добавьте слой приложения:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">mkdir</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -p</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> app</span></span>
|
||||
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">printf</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "Application code v1\\n"</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> ></span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> app/app.txt</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> add</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> app/app.txt</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> commit</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -m</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "feat: добавить слой приложения"</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> push</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -u</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> master</span></span></code></pre></div><p>После этого история выглядит так:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>template: T1</span></span>
|
||||
<span class="line"><span>master: T1---A1</span></span></code></pre></div><p>Где <code>T1</code> — коммит шаблона, а <code>A1</code> — коммит приложения.</p><h2 id="настроить-pull-и-push-для-template" tabindex="-1">Настроить pull и push для template <a class="header-anchor" href="#настроить-pull-и-push-для-template" aria-label="Permalink to "Настроить pull и push для template""></a></h2><p>Можно сделать так, чтобы на ветке <code>template</code>:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>git pull тянул из templates/master</span></span>
|
||||
<span class="line"><span>git push пушил в origin/template</span></span></code></pre></div><p>Команды:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> config</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> branch.template.remote</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> templates</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> config</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> branch.template.merge</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> refs/heads/master</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> config</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> branch.template.pushRemote</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin</span></span></code></pre></div><p>Дополнительно можно запретить случайный push в репозиторий шаблона:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> remote</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> set-url</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --push</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> templates</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> DISABLED</span></span></code></pre></div><h2 id="дальше" tabindex="-1">Дальше <a class="header-anchor" href="#дальше" aria-label="Permalink to "Дальше""></a></h2><p>После первичной настройки постоянные ветки такие:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>template = чистый шаблон</span></span>
|
||||
<span class="line"><span>master = приложение</span></span></code></pre></div><p>Обновления шаблона выполняются через временные ветки <code>sync/*</code> по инструкции <a href="./../workflows/update-template">Обычное обновление шаблона</a>.</p>`,37)])])}const c=a(p,[["render",n]]);export{F as __pageData,c as default};
|
||||
@@ -0,0 +1 @@
|
||||
import{_ as a,o as i,c as t,ae as e}from"./chunks/framework.B1nRs-GM.js";const F=JSON.parse('{"title":"Новый проект от шаблона","description":"Старт нового приложения от шаблонного репозитория с правильной историей веток.","frontmatter":{"title":"Новый проект от шаблона","description":"Старт нового приложения от шаблонного репозитория с правильной историей веток."},"headers":[],"relativePath":"setup/clean-repository.md","filePath":"setup/clean-repository.md"}'),p={name:"setup/clean-repository.md"};function n(l,s,h,k,d,r){return i(),t("div",null,[...s[0]||(s[0]=[e("",37)])])}const c=a(p,[["render",n]]);export{F as __pageData,c as default};
|
||||
@@ -0,0 +1,17 @@
|
||||
import{_ as a,o as i,c as t,ae as e}from"./chunks/framework.B1nRs-GM.js";const g=JSON.parse('{"title":"Миграция существующего master","description":"Как одноразово связать master приложения с историей шаблона, если проект был создан отдельно.","frontmatter":{"title":"Миграция существующего master","description":"Как одноразово связать master приложения с историей шаблона, если проект был создан отдельно."},"headers":[],"relativePath":"setup/existing-master-migration.md","filePath":"setup/existing-master-migration.md"}'),p={name:"setup/existing-master-migration.md"};function n(h,s,l,k,d,r){return i(),t("div",null,[...s[0]||(s[0]=[e(`<div style="display:none;" hidden="true" aria-hidden="true">Are you an LLM? You can read better optimized documentation at /template-sync-strategy/setup/existing-master-migration.md for this page in Markdown format</div><h1 id="миграция-существующего-master" tabindex="-1">Миграция существующего master <a class="header-anchor" href="#миграция-существующего-master" aria-label="Permalink to "Миграция существующего master""></a></h1><p>Этот сценарий нужен, если в репозитории приложения уже есть <code>master</code>, но он был создан не от шаблона.</p><h2 id="проблема" tabindex="-1">Проблема <a class="header-anchor" href="#проблема" aria-label="Permalink to "Проблема""></a></h2><p>Если <code>master</code> приложения и <code>template</code> имеют разные корневые коммиты, Git видит две несвязанные истории.</p><p>Плохое состояние:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>template: T1---T2---T3</span></span>
|
||||
<span class="line"><span></span></span>
|
||||
<span class="line"><span>master: A1---A2</span></span></code></pre></div><p>При попытке выполнить обычный merge Git может ответить:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>fatal: отказ слияния несвязанных историй изменений</span></span></code></pre></div><p>Это означает, что у веток нет общего предка.</p><h2 id="цель-миграции" tabindex="-1">Цель миграции <a class="header-anchor" href="#цель-миграции" aria-label="Permalink to "Цель миграции""></a></h2><p>Нужно один раз связать истории, чтобы дальше обновления шаблона шли обычным merge-процессом.</p><p>После миграции история будет выглядеть примерно так:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>template: T1---T2---T3</span></span>
|
||||
<span class="line"><span> \\</span></span>
|
||||
<span class="line"><span>master: A1---A2-----M</span></span></code></pre></div><p>Где <code>M</code> — одноразовый merge-коммит, который связал историю приложения с историей шаблона.</p><h2 id="подключить-репозитории-шаблона" tabindex="-1">Подключить репозиторий шаблона <a class="header-anchor" href="#подключить-репозитории-шаблона" aria-label="Permalink to "Подключить репозиторий шаблона""></a></h2><p>В репозитории приложения:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">cd</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> /path/to/app-repo</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> remote</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> add</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> templates</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> <</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">template-repo-ur</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">l</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">></span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> fetch</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> templates</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> fetch</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin</span></span></code></pre></div><p>Если remote <code>templates</code> уже существует:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> fetch</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> templates</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> fetch</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin</span></span></code></pre></div><h2 id="создать-или-обновить-template" tabindex="-1">Создать или обновить template <a class="header-anchor" href="#создать-или-обновить-template" aria-label="Permalink to "Создать или обновить template""></a></h2><p>Если ветки <code>template</code> ещё нет:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> switch</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -c</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> template</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> templates/master</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> push</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -u</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> template</span></span></code></pre></div><p>Если ветка <code>template</code> уже есть:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> switch</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> template</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> merge</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --ff-only</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> templates/master</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> push</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> template</span></span></code></pre></div><p>Опционально настройте удобное поведение <code>pull</code> и <code>push</code>:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> config</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> branch.template.remote</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> templates</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> config</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> branch.template.merge</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> refs/heads/master</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> config</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> branch.template.pushRemote</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> remote</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> set-url</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --push</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> templates</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> DISABLED</span></span></code></pre></div><h2 id="связать-master-с-template" tabindex="-1">Связать master с template <a class="header-anchor" href="#связать-master-с-template" aria-label="Permalink to "Связать master с template""></a></h2><p>Создайте временную ветку от текущего приложения:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> fetch</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> switch</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -c</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> sync/bootstrap-template</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin/master</span></span></code></pre></div><p>Слейте шаблон с разрешением несвязанных историй:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> merge</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --allow-unrelated-histories</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin/template</span></span></code></pre></div><p>Если есть конфликты, решите их в ветке <code>sync/bootstrap-template</code>:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> add</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> commit</span></span></code></pre></div><p>Если конфликтов не было, Git сам создаст merge-коммит.</p><p>Запушьте ветку:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> push</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -u</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> sync/bootstrap-template</span></span></code></pre></div><p>Дальше через UI или локально смержите:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>sync/bootstrap-template -> master</span></span></code></pre></div><h2 id="что-проверить-перед-merge" tabindex="-1">Что проверить перед merge <a class="header-anchor" href="#что-проверить-перед-merge" aria-label="Permalink to "Что проверить перед merge""></a></h2><p>Посмотрите граф истории:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --no-pager</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> log</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --oneline</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --graph</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --decorate</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --all</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --max-count=50</span></span></code></pre></div><p>Убедитесь, что <code>sync/bootstrap-template</code> содержит и историю приложения, и историю шаблона.</p><p>Посмотрите итоговый diff:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --no-pager</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> diff</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin/master...sync/bootstrap-template</span></span></code></pre></div><h2 id="когда-миграцию-делать-не-стоит" tabindex="-1">Когда миграцию делать не стоит <a class="header-anchor" href="#когда-миграцию-делать-не-стоит" aria-label="Permalink to "Когда миграцию делать не стоит""></a></h2><p>Не стоит связывать истории, если приложение только что создано и его можно безопасно пересоздать от шаблона.</p><p>Для нового проекта лучше сделать чистый старт по инструкции <a href="./clean-repository">Новый проект от шаблона</a>.</p>`,48)])])}const F=a(p,[["render",n]]);export{g as __pageData,F as default};
|
||||
@@ -0,0 +1 @@
|
||||
import{_ as a,o as i,c as t,ae as e}from"./chunks/framework.B1nRs-GM.js";const g=JSON.parse('{"title":"Миграция существующего master","description":"Как одноразово связать master приложения с историей шаблона, если проект был создан отдельно.","frontmatter":{"title":"Миграция существующего master","description":"Как одноразово связать master приложения с историей шаблона, если проект был создан отдельно."},"headers":[],"relativePath":"setup/existing-master-migration.md","filePath":"setup/existing-master-migration.md"}'),p={name:"setup/existing-master-migration.md"};function n(h,s,l,k,d,r){return i(),t("div",null,[...s[0]||(s[0]=[e("",48)])])}const F=a(p,[["render",n]]);export{g as __pageData,F as default};
|
||||
1
public/template-sync-strategy/assets/style.CSIvdBoa.css
Normal file
1
public/template-sync-strategy/assets/style.CSIvdBoa.css
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
|
||||
import{_ as a,o as e,c as i,ae as t}from"./chunks/framework.B1nRs-GM.js";const k=JSON.parse('{"title":"Решение конфликтов","description":"Почему конфликты при обновлении шаблона должны решаться только в sync-ветках.","frontmatter":{"title":"Решение конфликтов","description":"Почему конфликты при обновлении шаблона должны решаться только в sync-ветках."},"headers":[],"relativePath":"workflows/resolve-conflicts.md","filePath":"workflows/resolve-conflicts.md"}'),n={name:"workflows/resolve-conflicts.md"};function l(p,s,o,h,d,c){return e(),i("div",null,[...s[0]||(s[0]=[t(`<div style="display:none;" hidden="true" aria-hidden="true">Are you an LLM? You can read better optimized documentation at /template-sync-strategy/workflows/resolve-conflicts.md for this page in Markdown format</div><h1 id="решение-конфликтов" tabindex="-1">Решение конфликтов <a class="header-anchor" href="#решение-конфликтов" aria-label="Permalink to "Решение конфликтов""></a></h1><p>Конфликт при обновлении шаблона — нормальная ситуация. Важно не то, что конфликт возник, а где он возник.</p><p>Правильное место для конфликтов — временная ветка <code>sync/*</code>.</p><h2 id="пример" tabindex="-1">Пример <a class="header-anchor" href="#пример" aria-label="Permalink to "Пример""></a></h2><p>Шаблон поменял строку в <code>README.md</code>:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>Base template version: template-conflict-v10</span></span></code></pre></div><p>Приложение поменяло ту же строку иначе:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>Base template version: application-conflict-v10</span></span></code></pre></div><p>При merge <code>origin/template</code> в <code>sync/update-template-v10</code> появится конфликт:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span><<<<<<< HEAD</span></span>
|
||||
<span class="line"><span>Base template version: application-conflict-v10</span></span>
|
||||
<span class="line"><span>=======</span></span>
|
||||
<span class="line"><span>Base template version: template-conflict-v10</span></span>
|
||||
<span class="line"><span>>>>>>>> origin/template</span></span></code></pre></div><p>Это правильное место конфликта: <code>master</code> ещё не изменён, <code>template</code> остаётся чистой, а итоговое решение можно проверить в PR/MR.</p><h2 id="как-решать" tabindex="-1">Как решать <a class="header-anchor" href="#как-решать" aria-label="Permalink to "Как решать""></a></h2><ol><li>Оставайтесь в ветке <code>sync/*</code>.</li><li>Разберите конфликт по смыслу: что должно остаться в приложении после обновления шаблона.</li><li>Удалите conflict markers.</li><li>Проверьте проект локально.</li><li>Закоммитьте результат.</li></ol><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> status</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> add</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> commit</span></span></code></pre></div><h2 id="что-нельзя-делать" tabindex="-1">Что нельзя делать <a class="header-anchor" href="#что-нельзя-делать" aria-label="Permalink to "Что нельзя делать""></a></h2><p>Нельзя переносить conflict resolve в <code>template</code>.</p><p><code>template</code> должна совпадать с шаблоном. Если решение конфликта попадёт туда, она перестанет быть эталоном и дальнейшие обновления станут менее предсказуемыми.</p><p>Нельзя решать конфликт прямо в <code>master</code>, потому что основная ветка приложения должна получать только проверенный результат через PR/MR.</p><h2 id="что-проверить-после-resolve" tabindex="-1">Что проверить после resolve <a class="header-anchor" href="#что-проверить-после-resolve" aria-label="Permalink to "Что проверить после resolve""></a></h2><p>Посмотрите статус:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> status</span></span></code></pre></div><p>Посмотрите diff относительно текущего приложения:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --no-pager</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> diff</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin/master...HEAD</span></span></code></pre></div><p>Посмотрите граф:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --no-pager</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> log</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --oneline</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --graph</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --decorate</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --all</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --max-count=50</span></span></code></pre></div>`,26)])])}const g=a(n,[["render",l]]);export{k as __pageData,g as default};
|
||||
@@ -0,0 +1 @@
|
||||
import{_ as a,o as e,c as i,ae as t}from"./chunks/framework.B1nRs-GM.js";const k=JSON.parse('{"title":"Решение конфликтов","description":"Почему конфликты при обновлении шаблона должны решаться только в sync-ветках.","frontmatter":{"title":"Решение конфликтов","description":"Почему конфликты при обновлении шаблона должны решаться только в sync-ветках."},"headers":[],"relativePath":"workflows/resolve-conflicts.md","filePath":"workflows/resolve-conflicts.md"}'),n={name:"workflows/resolve-conflicts.md"};function l(p,s,o,h,d,c){return e(),i("div",null,[...s[0]||(s[0]=[t("",26)])])}const g=a(n,[["render",l]]);export{k as __pageData,g as default};
|
||||
@@ -0,0 +1,9 @@
|
||||
import{_ as a,o as i,c as e,ae as t}from"./chunks/framework.B1nRs-GM.js";const g=JSON.parse('{"title":"Review и merge","description":"Как проверять и вливать sync-ветку с обновлением шаблона в master приложения.","frontmatter":{"title":"Review и merge","description":"Как проверять и вливать sync-ветку с обновлением шаблона в master приложения."},"headers":[],"relativePath":"workflows/review-and-merge.md","filePath":"workflows/review-and-merge.md"}'),n={name:"workflows/review-and-merge.md"};function p(l,s,h,r,d,o){return i(),e("div",null,[...s[0]||(s[0]=[t(`<div style="display:none;" hidden="true" aria-hidden="true">Are you an LLM? You can read better optimized documentation at /template-sync-strategy/workflows/review-and-merge.md for this page in Markdown format</div><h1 id="review-и-merge" tabindex="-1">Review и merge <a class="header-anchor" href="#review-и-merge" aria-label="Permalink to "Review и merge""></a></h1><p>После подготовки <code>sync/*</code> ветки обновление шаблона должно попасть в <code>master</code> через PR/MR.</p><h2 id="создать-pr-mr" tabindex="-1">Создать PR/MR <a class="header-anchor" href="#создать-pr-mr" aria-label="Permalink to "Создать PR/MR""></a></h2><p>Параметры:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>source: sync/update-template-vX</span></span>
|
||||
<span class="line"><span>target: master</span></span></code></pre></div><p>Цель review — увидеть:</p><ul><li>какие изменения пришли из шаблона;</li><li>какие конфликтные решения были сделаны в <code>sync/*</code>;</li><li>не попали ли в обновление лишние изменения приложения;</li><li>проходят ли проверки проекта.</li></ul><h2 id="настроики-merge" tabindex="-1">Настройки merge <a class="header-anchor" href="#настроики-merge" aria-label="Permalink to "Настройки merge""></a></h2><p>Для sync-PR/MR важно:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>squash = off</span></span>
|
||||
<span class="line"><span>fast-forward merge = хорошо</span></span>
|
||||
<span class="line"><span>merge commit = допустимо</span></span>
|
||||
<span class="line"><span>squash merge = нельзя</span></span></code></pre></div><p>Squash нельзя использовать, потому что он может уничтожить связь истории <code>master</code> с историей <code>template</code>. Особенно это критично после миграционного <code>sync/bootstrap-template</code>.</p><h2 id="проверки-перед-merge" tabindex="-1">Проверки перед merge <a class="header-anchor" href="#проверки-перед-merge" aria-label="Permalink to "Проверки перед merge""></a></h2><p>Проверьте граф истории:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --no-pager</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> log</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --oneline</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --graph</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --decorate</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --all</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --max-count=50</span></span></code></pre></div><p>Проверьте итоговый diff:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --no-pager</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> diff</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin/master...sync/update-template-vX</span></span></code></pre></div><p>Проверьте проект обычными командами конкретного приложения, например:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> run</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> lint</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> run</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> build</span></span></code></pre></div><h2 id="после-merge" tabindex="-1">После merge <a class="header-anchor" href="#после-merge" aria-label="Permalink to "После merge""></a></h2><p>После успешного merge в <code>master</code> можно удалить временную ветку:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> branch</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -d</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> sync/update-template-vX</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> push</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --delete</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> sync/update-template-vX</span></span></code></pre></div><p>Проверьте, что <code>master</code> теперь содержит обновление шаблона:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> fetch</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --no-pager</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> log</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin/template..origin/master</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --oneline</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --no-pager</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> diff</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin/template...origin/master</span></span></code></pre></div>`,24)])])}const c=a(n,[["render",p]]);export{g as __pageData,c as default};
|
||||
@@ -0,0 +1 @@
|
||||
import{_ as a,o as i,c as e,ae as t}from"./chunks/framework.B1nRs-GM.js";const g=JSON.parse('{"title":"Review и merge","description":"Как проверять и вливать sync-ветку с обновлением шаблона в master приложения.","frontmatter":{"title":"Review и merge","description":"Как проверять и вливать sync-ветку с обновлением шаблона в master приложения."},"headers":[],"relativePath":"workflows/review-and-merge.md","filePath":"workflows/review-and-merge.md"}'),n={name:"workflows/review-and-merge.md"};function p(l,s,h,r,d,o){return i(),e("div",null,[...s[0]||(s[0]=[t("",24)])])}const c=a(n,[["render",p]]);export{g as __pageData,c as default};
|
||||
@@ -0,0 +1,17 @@
|
||||
import{_ as a,o as i,c as t,ae as e}from"./chunks/framework.B1nRs-GM.js";const c=JSON.parse('{"title":"Обычное обновление шаблона","description":"Повторяемый процесс доставки изменений шаблона в приложение после первичной настройки.","frontmatter":{"title":"Обычное обновление шаблона","description":"Повторяемый процесс доставки изменений шаблона в приложение после первичной настройки."},"headers":[],"relativePath":"workflows/update-template.md","filePath":"workflows/update-template.md"}'),p={name:"workflows/update-template.md"};function n(l,s,h,k,d,r){return i(),t("div",null,[...s[0]||(s[0]=[e(`<div style="display:none;" hidden="true" aria-hidden="true">Are you an LLM? You can read better optimized documentation at /template-sync-strategy/workflows/update-template.md for this page in Markdown format</div><h1 id="обычное-обновление-шаблона" tabindex="-1">Обычное обновление шаблона <a class="header-anchor" href="#обычное-обновление-шаблона" aria-label="Permalink to "Обычное обновление шаблона""></a></h1><p>Эта инструкция подходит после любого стартового сценария:</p><ul><li><a href="./../setup/clean-repository">Новый проект от шаблона</a>.</li><li><a href="./../setup/existing-master-migration">Миграция существующего master</a>.</li></ul><p>Целевой маршрут:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>templates/master -> template -> sync/* -> master</span></span></code></pre></div><h2 id="_1-обновить-слепок-шаблона" tabindex="-1">1. Обновить слепок шаблона <a class="header-anchor" href="#_1-обновить-слепок-шаблона" aria-label="Permalink to "1. Обновить слепок шаблона""></a></h2><p>В репозитории приложения:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">cd</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> /path/to/app-repo</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> switch</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> template</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> pull</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --ff-only</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> push</span></span></code></pre></div><p>Этот вариант работает, если для ветки <code>template</code> настроено:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>pull из templates/master</span></span>
|
||||
<span class="line"><span>push в origin/template</span></span></code></pre></div><p>Явная форма без зависимости от tracking-настроек:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> fetch</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> templates</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> switch</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> template</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> merge</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --ff-only</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> templates/master</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> push</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> template</span></span></code></pre></div><p>Если <code>--ff-only</code> падает, значит <code>template</code> перестал быть чистым слепком шаблона. Остановитесь и разберите причину до продолжения.</p><p>Проверьте, что <code>origin/template</code> обновился до шаблона:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> fetch</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> fetch</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> templates</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --no-pager</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> log</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --oneline</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -1</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin/template</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --no-pager</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> log</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --oneline</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -1</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> templates/master</span></span></code></pre></div><p>Оба коммита должны совпадать.</p><h2 id="_2-создать-ветку-обновления-приложения" tabindex="-1">2. Создать ветку обновления приложения <a class="header-anchor" href="#_2-создать-ветку-обновления-приложения" aria-label="Permalink to "2. Создать ветку обновления приложения""></a></h2><p>После обновления <code>template</code> создайте временную ветку от текущего приложения:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> fetch</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> switch</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -c</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> sync/update-template-v2</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin/master</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> merge</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin/template</span></span></code></pre></div><p>Имя ветки можно менять под версию или дату:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>sync/update-template-v2</span></span>
|
||||
<span class="line"><span>sync/update-template-2026-05-09</span></span>
|
||||
<span class="line"><span>sync/update-template-1.8.0</span></span></code></pre></div><p>Проверьте, что временная ветка реально отличается от <code>origin/master</code> изменениями шаблона:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --no-pager</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> diff</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --stat</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin/master...HEAD</span></span></code></pre></div><p>Если diff пустой, значит обновлённый <code>origin/template</code> не был влит в <code>sync/*</code> ветку или в шаблоне нет новых изменений.</p><h2 id="_3-решить-конфликты" tabindex="-1">3. Решить конфликты <a class="header-anchor" href="#_3-решить-конфликты" aria-label="Permalink to "3. Решить конфликты""></a></h2><p>Если есть конфликты, решайте их именно в <code>sync/*</code>.</p><p>После решения конфликтов:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> add</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span></span>
|
||||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> commit</span></span></code></pre></div><p>Если конфликтов не было, Git сам создаст merge-коммит или выполнит fast-forward, в зависимости от истории.</p><h2 id="_4-запушить-sync-ветку" tabindex="-1">4. Запушить sync-ветку <a class="header-anchor" href="#_4-запушить-sync-ветку" aria-label="Permalink to "4. Запушить sync-ветку""></a></h2><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">git</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> push</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -u</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> origin</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> sync/update-template-v2</span></span></code></pre></div><p>Дальше откройте PR/MR:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>source: sync/update-template-v2</span></span>
|
||||
<span class="line"><span>target: master</span></span></code></pre></div><p>Правила merge описаны в <a href="./review-and-merge">Review и merge</a>.</p>`,35)])])}const g=a(p,[["render",n]]);export{c as __pageData,g as default};
|
||||
@@ -0,0 +1 @@
|
||||
import{_ as a,o as i,c as t,ae as e}from"./chunks/framework.B1nRs-GM.js";const c=JSON.parse('{"title":"Обычное обновление шаблона","description":"Повторяемый процесс доставки изменений шаблона в приложение после первичной настройки.","frontmatter":{"title":"Обычное обновление шаблона","description":"Повторяемый процесс доставки изменений шаблона в приложение после первичной настройки."},"headers":[],"relativePath":"workflows/update-template.md","filePath":"workflows/update-template.md"}'),p={name:"workflows/update-template.md"};function n(l,s,h,k,d,r){return i(),t("div",null,[...s[0]||(s[0]=[e("",35)])])}const g=a(p,[["render",n]]);export{c as __pageData,g as default};
|
||||
29
public/template-sync-strategy/concepts/model.html
Normal file
29
public/template-sync-strategy/concepts/model.html
Normal file
File diff suppressed because one or more lines are too long
72
public/template-sync-strategy/concepts/model.md
Normal file
72
public/template-sync-strategy/concepts/model.md
Normal file
@@ -0,0 +1,72 @@
|
||||
---
|
||||
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 <template-repo-url>
|
||||
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.
|
||||
28
public/template-sync-strategy/concepts/rules.html
Normal file
28
public/template-sync-strategy/concepts/rules.html
Normal file
File diff suppressed because one or more lines are too long
49
public/template-sync-strategy/concepts/rules.md
Normal file
49
public/template-sync-strategy/concepts/rules.md
Normal file
@@ -0,0 +1,49 @@
|
||||
---
|
||||
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` — эталонный слепок оригинального шаблона.
|
||||
|
||||
Если в неё попадает локальное решение конфликта или изменение приложения, она перестаёт отвечать на вопрос: “какая версия шаблона сейчас подключена к приложению?”.
|
||||
|
||||
После этого ломается главная граница ответственности: шаблон отдельно, приложение отдельно, конфликтная зона отдельно.
|
||||
26
public/template-sync-strategy/concepts/why.html
Normal file
26
public/template-sync-strategy/concepts/why.html
Normal file
File diff suppressed because one or more lines are too long
46
public/template-sync-strategy/concepts/why.md
Normal file
46
public/template-sync-strategy/concepts/why.md
Normal file
@@ -0,0 +1,46 @@
|
||||
---
|
||||
url: /template-sync-strategy/concepts/why.md
|
||||
description: >-
|
||||
Почему шаблону нужен процесс обновления, а не только быстрый старт нового
|
||||
проекта.
|
||||
---
|
||||
|
||||
# Зачем это нужно
|
||||
|
||||
Шаблон закрывает повторяющуюся техническую базу проекта: CI/CD, Dockerfile, зависимости, lint, build, структуру каталогов и базовую документацию.
|
||||
|
||||
Это снимает рутину на старте. Команде не нужно каждый раз заново собирать одинаковый технический каркас.
|
||||
|
||||
## Проблема после старта
|
||||
|
||||
Создать проект легко. Поддерживать 10-20 проектов сложнее.
|
||||
|
||||
Сначала проекты похожи. Потом они начинают расходиться:
|
||||
|
||||
* В одном проекте обновили CI, в другом забыли.
|
||||
* В одном проекте Dockerfile остался из шаблона, в другом его локально поправили.
|
||||
* В одном проекте зависимости уже свежие, в другом остались старые версии.
|
||||
* В одном проекте изменения шаблона перенесли руками, в другом потеряли.
|
||||
|
||||
Без процесса обновления шаблон перестаёт быть общей основой. Он остаётся только способом быстро создать первый коммит.
|
||||
|
||||
## Что ломается без стратегии
|
||||
|
||||
Когда шаблон нельзя нормально обновлять:
|
||||
|
||||
* проекты начинают жить своей жизнью;
|
||||
* граница между шаблоном и приложением теряется;
|
||||
* обновления превращаются в ручное копирование;
|
||||
* конфликты решаются прямо в рабочих ветках;
|
||||
* становится непонятно, какой проект на какой версии шаблона;
|
||||
* Git-история перестаёт быть источником правды.
|
||||
|
||||
Это особенно больно, когда приложений много. Для одного проекта ручной перенос ещё можно пережить. Для набора проектов нужен единый маршрут обновления.
|
||||
|
||||
## Цель стратегии
|
||||
|
||||
Стратегия не пытается убрать конфликты полностью. Она делает так, чтобы конфликты возникали в предсказуемом месте, проходили review и не ломали чистую ветку шаблона.
|
||||
|
||||
Главная формулировка:
|
||||
|
||||
> Шаблон должен обновляться так же контролируемо, как обычная фича: через ветку, проверку и PR/MR.
|
||||
1
public/template-sync-strategy/hashmap.json
Normal file
1
public/template-sync-strategy/hashmap.json
Normal file
@@ -0,0 +1 @@
|
||||
{"concepts_model.md":"C805A9As","concepts_rules.md":"QraT4IhZ","concepts_why.md":"akfw90Fj","index.md":"C5Q_ZnE3","overview.md":"DOeHHuHO","reference_cheatsheet.md":"0TzKSaSb","reference_glossary.md":"DLD-b2Ke","reference_troubleshooting.md":"BrYSpYuW","setup_clean-repository.md":"CPqmBfph","setup_existing-master-migration.md":"BQ5VImS9","workflows_resolve-conflicts.md":"CujNWdsi","workflows_review-and-merge.md":"D5KhlAbu","workflows_update-template.md":"C8s1FFCq"}
|
||||
26
public/template-sync-strategy/index.html
Normal file
26
public/template-sync-strategy/index.html
Normal file
File diff suppressed because one or more lines are too long
1009
public/template-sync-strategy/llms-full.txt
Normal file
1009
public/template-sync-strategy/llms-full.txt
Normal file
File diff suppressed because it is too large
Load Diff
30
public/template-sync-strategy/llms.txt
Normal file
30
public/template-sync-strategy/llms.txt
Normal file
@@ -0,0 +1,30 @@
|
||||
# Template Sync Strategy
|
||||
|
||||
> Управляемое обновление проектов от шаблона
|
||||
|
||||
## Table of Contents
|
||||
|
||||
### Введение
|
||||
|
||||
- [Template Sync Strategy](/template-sync-strategy/overview.md): Управляемое обновление проектов от шаблона через чистую ветку template, временные sync-ветки и PR/MR.
|
||||
- [Зачем это нужно](/template-sync-strategy/concepts/why.md): Почему шаблону нужен процесс обновления, а не только быстрый старт нового проекта.
|
||||
- [Модель веток](/template-sync-strategy/concepts/model.md): Роли веток и remote в стратегии обновления проекта от шаблона.
|
||||
- [Правила процесса](/template-sync-strategy/concepts/rules.md): Набор правил, который удерживает template чистой, а обновления шаблона контролируемыми.
|
||||
|
||||
### Настройка
|
||||
|
||||
- [Новый проект от шаблона](/template-sync-strategy/setup/clean-repository.md): Старт нового приложения от шаблонного репозитория с правильной историей веток.
|
||||
- [Миграция существующего master](/template-sync-strategy/setup/existing-master-migration.md): Как одноразово связать master приложения с историей шаблона, если проект был создан отдельно.
|
||||
|
||||
### Рабочие процессы
|
||||
|
||||
- [Обычное обновление шаблона](/template-sync-strategy/workflows/update-template.md): Повторяемый процесс доставки изменений шаблона в приложение после первичной настройки.
|
||||
- [Решение конфликтов](/template-sync-strategy/workflows/resolve-conflicts.md): Почему конфликты при обновлении шаблона должны решаться только в sync-ветках.
|
||||
- [Review и merge](/template-sync-strategy/workflows/review-and-merge.md): Как проверять и вливать sync-ветку с обновлением шаблона в master приложения.
|
||||
|
||||
### Справочник
|
||||
|
||||
- [Памятка](/template-sync-strategy/reference/cheatsheet.md): Короткий набор команд для регулярного обновления приложения от шаблона.
|
||||
- [Troubleshooting](/template-sync-strategy/reference/troubleshooting.md): Типовые ошибки при обновлении проекта от шаблона и способы диагностики.
|
||||
- [Глоссарий](/template-sync-strategy/reference/glossary.md): Термины, которые используются в Template Sync Strategy.
|
||||
|
||||
26
public/template-sync-strategy/overview.html
Normal file
26
public/template-sync-strategy/overview.html
Normal file
File diff suppressed because one or more lines are too long
49
public/template-sync-strategy/overview.md
Normal file
49
public/template-sync-strategy/overview.md
Normal file
@@ -0,0 +1,49 @@
|
||||
---
|
||||
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) — основные термины.
|
||||
32
public/template-sync-strategy/reference/cheatsheet.html
Normal file
32
public/template-sync-strategy/reference/cheatsheet.html
Normal file
File diff suppressed because one or more lines are too long
75
public/template-sync-strategy/reference/cheatsheet.md
Normal file
75
public/template-sync-strategy/reference/cheatsheet.md
Normal file
@@ -0,0 +1,75 @@
|
||||
---
|
||||
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`.
|
||||
26
public/template-sync-strategy/reference/glossary.html
Normal file
26
public/template-sync-strategy/reference/glossary.html
Normal file
File diff suppressed because one or more lines are too long
52
public/template-sync-strategy/reference/glossary.md
Normal file
52
public/template-sync-strategy/reference/glossary.md
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
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 <template-repo-url>
|
||||
```
|
||||
|
||||
## 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`.
|
||||
34
public/template-sync-strategy/reference/troubleshooting.html
Normal file
34
public/template-sync-strategy/reference/troubleshooting.html
Normal file
File diff suppressed because one or more lines are too long
102
public/template-sync-strategy/reference/troubleshooting.md
Normal file
102
public/template-sync-strategy/reference/troubleshooting.md
Normal file
@@ -0,0 +1,102 @@
|
||||
---
|
||||
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
|
||||
```
|
||||
43
public/template-sync-strategy/setup/clean-repository.html
Normal file
43
public/template-sync-strategy/setup/clean-repository.html
Normal file
File diff suppressed because one or more lines are too long
119
public/template-sync-strategy/setup/clean-repository.md
Normal file
119
public/template-sync-strategy/setup/clean-repository.md
Normal file
@@ -0,0 +1,119 @@
|
||||
---
|
||||
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 <template-repo-url>
|
||||
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).
|
||||
File diff suppressed because one or more lines are too long
146
public/template-sync-strategy/setup/existing-master-migration.md
Normal file
146
public/template-sync-strategy/setup/existing-master-migration.md
Normal file
@@ -0,0 +1,146 @@
|
||||
---
|
||||
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 <template-repo-url>
|
||||
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).
|
||||
0
public/template-sync-strategy/vp-icons.css
Normal file
0
public/template-sync-strategy/vp-icons.css
Normal file
File diff suppressed because one or more lines are too long
78
public/template-sync-strategy/workflows/resolve-conflicts.md
Normal file
78
public/template-sync-strategy/workflows/resolve-conflicts.md
Normal file
@@ -0,0 +1,78 @@
|
||||
---
|
||||
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
|
||||
```
|
||||
File diff suppressed because one or more lines are too long
75
public/template-sync-strategy/workflows/review-and-merge.md
Normal file
75
public/template-sync-strategy/workflows/review-and-merge.md
Normal file
@@ -0,0 +1,75 @@
|
||||
---
|
||||
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
|
||||
```
|
||||
42
public/template-sync-strategy/workflows/update-template.html
Normal file
42
public/template-sync-strategy/workflows/update-template.html
Normal file
File diff suppressed because one or more lines are too long
113
public/template-sync-strategy/workflows/update-template.md
Normal file
113
public/template-sync-strategy/workflows/update-template.md
Normal file
@@ -0,0 +1,113 @@
|
||||
---
|
||||
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).
|
||||
@@ -269,6 +269,12 @@
|
||||
fill: color-mix(in srgb, currentColor 18%, transparent);
|
||||
}
|
||||
|
||||
.docIconGitBranch {
|
||||
display: block;
|
||||
background: currentColor;
|
||||
mask: url('/icons/git-branch-outline.svg') center / contain no-repeat;
|
||||
}
|
||||
|
||||
.docMeta {
|
||||
margin-bottom: 5px;
|
||||
color: var(--doc-accent);
|
||||
|
||||
@@ -229,6 +229,10 @@ function DocIcon({ mark }: { mark: string }) {
|
||||
)
|
||||
}
|
||||
|
||||
if (mark === 'TS') {
|
||||
return <span className="docIcon docIconGitBranch" aria-hidden="true" />
|
||||
}
|
||||
|
||||
return <span>{mark}</span>
|
||||
}
|
||||
|
||||
|
||||
@@ -66,4 +66,17 @@ export const docs: DocCard[] = [
|
||||
{ label: 'llms-full.txt', href: '/figma-adaptive-standards/llms-full.txt' },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Template Sync Strategy',
|
||||
label: 'Стратегия',
|
||||
mark: 'TS',
|
||||
description: 'Стратегия создания проектов от шаблона и долгосрочного обновления приложений через чистую ветку template, временные sync-ветки и PR/MR без ручного копирования файлов.',
|
||||
href: '/template-sync-strategy/',
|
||||
status: 'Доступно',
|
||||
accent: 'cyan',
|
||||
links: [
|
||||
{ label: 'llms.txt', href: '/template-sync-strategy/llms.txt' },
|
||||
{ label: 'llms-full.txt', href: '/template-sync-strategy/llms-full.txt' },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user