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