От хаоса к порядку: как и зачем мы перешли на модифицированную архитектуру ведения Git
И снова привет, Хабр! Я Артем Клещев, технический писатель в СберТехе.
Недавно я рассказал, как построить удобную архитектуру репозитория продукта и вести единый источник в Docs-as-Code вместо разрозненных комплектов документации. Сегодня хочу поделиться тем, как мы добавили к такой архитектуре новый для нас, модифицированный процесс ведения Git — Feature Branch Workflow — и значительно сократили время подготовки документации.
Расскажу, как этот метод версионирования помог нам упростить и ускорить работу. Обсудим, как можно удобно работать в единой ветке и выпускать несколько хотфиксов документации за день.
Объяснять буду на примерах из документации продукта Platform V DropApp — решения СберТеха для управления контейнерными приложениями.
Кратко: основы архитектуры Git
Большинство команд, которые работают в парадигме Docs-as-Code, пользуются Git. И мы не исключение. Мы создавали под задачу отдельную ветку, согласовывали по этой задаче pull request (PR, запрос на слияние) в релизную ветку — и так с каждой, даже незначительной задачей.
Нам хотелось ускорить этот процесс. Поэтому мы внедрили новый для нас метод версионирования, который учитывает наши цели, задачи и архитектуру репозитория с использованием шаблонов и директивы include (подробнее об этом здесь). Дальше расскажу, что имеем в виду под модифицированной моделью, какие преимущества нам дало внедрение такого метода — и какие можете получить вы, если внедрите его в свои процессы.
Какие возможности архитектуры Git мы использовали?
Единая ветка
Ведение истории версионирования в единой ветке — одно из основных преимуществ документации в едином пространстве Git. Оно позволяет:
-
уменьшать количество task-веток;
-
гибко регулировать ветки и задачи;
-
уменьшать количество конфликтов Git и связанных с ними ошибок;
-
наглядно отслеживать изменения в репозитории.
Pull requests
Архитектура ведения единой ветки также позволяет реализовать полные и наглядные pull request’ы на каждый релиз с отображением всех изменений:
-
создаётся основная, единая мастер-ветка;
-
при новом релизе новая релизная ветка откалывается от предыдущего релиза;
-
вносятся необходимые изменения в основную мастер-ветку;
-
создается pull request: «основная мастер-ветка → ветка нового релиза из шага 2».

Мы поняли: вести работу в одной ветке нам гораздо удобнее, чем прыгать из ветки в ветку и создавать новые задачи. Это не сильно заметно при малом количестве задач и изменений, но при десяти или двадцати задачах заметно облегчает жизнь: я вёл большую часть изменений в одной ветке, а отчётность — всего в нескольких задачах.
Отображение изменений в compare
Ещё одно преимущество ведения документации в едином пространстве — визуально-понятное и очевидное отображение всех изменений в compare (сравнении версий веток), diff (разнице состояний веток) и PR.
Это позволяет:
-
сократить количество создаваемых pull request’ов;
-
уменьшить количество конфликтов и связанных с ними ошибок;
-
видеть diff в любой момент, без необходимости каждый раз делать отдельный compare;
-
отслеживать историю изменений на единой странице pull request;
-
экономить время на согласованиях и проверках.

На себе ощутили: проверять PR, в котором все изменения видны, а не разнесены по десятку разных PR, — одно удовольствие. Замечания коллег при кросс-рецензировании — тоже в одном месте. С тех пор мой руководитель ни разу не просил сделать compare, чтобы увидеть сравнение, потому что знал: полное и наглядное сравнение лежит в едином PR.
Архитектура ведения Git: сравниваем варианты
А теперь посмотрим, как мы на практике применили эти особенности архитектуры Git. Но для начала сравню нашу старую и новую архитектуру ведения контроля версий Git, выделю преимущества и недостатки каждого варианта.
Старая архитектура Git
Под каждую задачу создаётся ветка от Release-branch. Ветка наполняется контентом и вливается в Release-branch. Новая релизная ветка New-Release-branch откалывается от предыдущей Release-branch.

Преимущества:
-
привычная схема;
-
в каждой задаче видны ссылаемые коммиты и pull request’ы.
Недостатки:
-
Временные затраты на создание, работу с дополнительными ветками и их удаление.
-
Большое количество конфликтов из-за выполнения задач «перекрёстным» методом (например, внесение изменений в один документ разными задачами).
-
Приходится каждый раз делать compare при необходимости diff.
-
Требуется создание новой ветки при изменении контента типа «Удаление» (например, удалить раздел, не входящий в данный релиз).
Наши релизные ветки защищены от изменения, что логично. Поэтому менять их мы можем только с помощью PR. Чтобы удалить слово или строку, мне приходилось создавать задачу, откалываться от релизной ветки, удалять, оставлять комментарий в задаче, закрывать её.
Наша новая архитектура Git
-
Основная разработка ведётся в Master-branch (главной ветке проекта).
-
При необходимости под разные задачи создаются разные ветки, наполняются контентом и вливаются в Master-branch. Этот шаг опциональный: когда нужно согласовать конкретное изменение с конкретным человеком, например, примечания к релизу с владельцем продукта.
-
На любом этапе создается pull request из Master-branch в Release-branch (мы создаём с самого старта релиза).
-
Новая релизная ветка New-Release-branch откалывается от предыдущей Release-branch. Работа продолжается в ветке Master-branch.
Сейчас я просто удаляю необходимое и оставляю комментарий в единой операционной задаче. Красота.

Преимущества:
-
Количество веток: в среднем я стал создавать на 11-13 веток (и связанных с ними задач) меньше.
-
Экономия времени на создании избыточных веток и pull request’ов: проверка в едином PR может проходить параллельно, а не в режиме «создал PR — проверили — создал новый PR».
-
Меньше конфликтов из-за временных затрат на выполнение задач в сторонних ветках «перекрестным» методом: например, таких конфликтов, как внесение изменений в один документ разными задачами.
-
Меньше ошибок из-за неправильно разрешённых конфликтов.
-
Можно гибко регулировать количество дополнительных веток и pull request’ов, так как пропадает необходимость создавать ветки на каждую задачу.
-
Более наглядное и лёгкое отслеживание ошибок. Единый PR и/или compare можно получить и при старой модели, но для этого необходимы дополнительные действия ко всем ранее созданным PR.
-
Не нужно создавать новую ветку при изменении контента типа «Удаление» (например, удаление раздела документации, не входящего в релиз), можно просто удалить лишнее без заведения дополнительной ветки.
-
Не нужно делать compare: единый pull request позволяет видеть diff в любой момент на протяжении всего релиза. Экономия, на первый взгляд, небольшая, ведь создать compare дело трёх минут. Но накопительный эффект ощутим: зачем каждый раз это делать, если всё сравнение уже есть в одном окне единого PR?
-
Вся история изменений на единой странице pull request. Если в старой модели я забуду, в каком PR коммит необходимого изменения, и буду долго его искать, то в новой — все мои коммиты на одной странице.
-
Экономия времени на согласованиях, проверках. Не нужно ждать проверки PR, чтобы его влить и снова отколоть ветку для изменений в том же файле. А проверяющему не нужно бегать по десяти-двадцати PR с проверкой: все проверки и изменения в одном месте.
-
При корректной настройке репозитория (запрет на удаление мастер-ветки) и внимательности пользователя новый вариант не уступает по надёжности хранения информации старой архитектуре.
-
Возможно создание дополнительных веток task-branch-N при необходимости или при наличии сторонних разработчиков.
-
Подсвечивание task-commit-N в задачах (при наличии такой функциональности в вашем task-tracker).
-
Тестирование документации по принципу «единого окна».
-
Контент не теряется при переносе в рамках множества задач, при решении конфликтов или по невнимательности.
-
Разные версии контента (например, разные сценарии для каждой версии) могут располагаться «рядом»; при «уравновешивании» лишнее удаляется.
Недостатки:
-
Новая архитектура ведения истории сохранений может быть непривычной.
-
Новым проверяющим (например, руководству или редакторам) тяжело будет погрузиться в архитектуру при первой проверке.
-
Дополнительное отслеживание разметки при расстановке комментариев директивы
include. -
Усложнение проектирования документации без утвержденной директивы тегирования
include.
Преимущества нового для нас метода ведения версий Git очевидны. Изменения вносятся в релизную ветку единым pull request: вы никогда не забудете и не пропустите давние изменения. Совместная работа становится удобнее: все мелкие изменения или изменения при работе нескольких человек будут вливаться в мастер-ветку и отображаться в едином pull request.
Как одновременно вести несколько релизов
Как я говорил, один из плюсов работы в единой ветке — возможность одновременно работать над несколькими релизами.
Проблема старой архитектуры заключается в том, что при одновременном, непоследовательном выпуске нескольких версий приходилось вручную вносить изменения ранее выпущенной версии. Например: контент из ещё не выпущенного хотфикса 1.1 нужно было вручную вносить в хотфикс 1.2, так как релиза ещё не было, а уже подходило время выпускать 1.2. При большом количестве хотфиксов и их высокой регулярности можно было запутаться и забыть внести контент одной версии в другую или даже удалить что-то из хотфикса более ранней версии.
Новая архитектура подразумевает, что контент всех единовременных хотфиксов вносится в одну ветку, хотфиксы разграничиваются директивой, а управление выпуском осуществляется только через публикацию, а не перенос контента.
Давайте посмотрим на конкретном примере.
-
Изначальный контент — раздел с существующим контентом ранних версий 1.0.0 и 1.1.0.

-
Разделять будем контент с версиями новых релизов K8ST (Test): 1.2.0, 1.2.1, 1.3.0.

Поставим условия:
-
В документации есть раздел с существующим контентом ранних версий 1.0.0 и 1.1.0.

-
Выход двух обновлений и одного хотфикса одним числом — 30.02.2025.
-
Контент обновлений вставляется в «середину» раздела.



-
Контент должен быть разделен на каждый релиз.
Попробуем пройтись по шагам:
Каталоги расположены следующим образом:

Шаг 1. За исходный (переиспользуемый) файл в каталоге шаблонов принимаем «4-one‑time‑release‑file.md».

Шаг 2. За тестируемый публикуемый файл в каталоге публичной ФСТЭК принимаем «4-one‑time‑release‑file.md».

Шаг 3. Наполняем тестируемый публикуемый файл первой директивой.

Шаг 4. Пробуем первую публикацию. Должен появиться раздел «Проверка одновременных релизов».

Соберём документацию только с существующим контентом выпущенных ранее версий:
Шаг 1. В единой ветке наполняем исходный файл комментариями в соответствии с контентом предыдущих версий.

Шаг 2. Наполняем тестируемый публикуемый файл директивой для сборки существующего контента.

Шаг 3. Публикуем. Убеждаемся, что результат соответствует ожиданиям.

Собирать документацию можно разными способами. Рассмотрим несколько вариантов.
Вариант 1. Соберём документацию только для релиза 1.2.0:
Шаг 1. Наполняем исходный файл комментариями в соответствии с потребностями публикации релиза 1.2.0.

Шаг 2. Наполняем тестируемый публикуемый файл директивой для сборки актуального контента.

Шаг 3. Публикуем. Убеждаемся, что результат соответствует ожиданиям.

Соберём документацию только для хотфикса 1.2.1:
Шаг 1. Наполняем исходный файл комментариями в соответствии с потребностями публикации хотфикса 1.2.1.

Шаг 2. Наполняем тестируемый публикуемый файл директивой для сборки актуального контента.

Шаг 3. Публикуем. Убеждаемся, что результат соответствует ожиданиям.

Соберём документацию только для релиза 1.3.0:
Шаг 1. Наполняем исходный файл комментариями в соответствии с потребностями публикации релиза 1.3.0.

Шаг 2. Наполняем тестируемый публикуемый файл директивой для сборки актуального контента.

Шаг 3. Публикуем. Убеждаемся, что результат соответствует ожиданиям.

Этот вариант показывает: хоть документация и выпускается, условно, «в один день», она выпускается по очереди, при соблюдении весьма простой разметки с помощью директивы include. Для этого нужно всего лишь добавить две строки комментариев и заменить две строки директивы: разметили уже написанный контент под первую версию, сделали коммит, опубликовали. Тут же, в единой ветке, разметили контент под вторую версию, сделали коммит, опубликовали. И каждый раз получаем полностью готовый к выпуску продукт.
Вариант 2. Разберём пример.
Шаг 1. Наполняем исходный файл комментариями в соответствии с потребностями публикации релиза 1.3.0. Обратите внимание: расстановка комментариев отличается от расстановки в предыдущей версии.

Шаг 2. Наполняем тестируемый публикуемый файл директивой для сборки актуального контента. Обратите внимание: расстановка директив отличается от расстановки в предыдущей версии.

Шаг 3. Публикуем. Убеждаемся, что результат соответствует ожиданиям.

Такой подход к выпуску может обеспечивать чуть более наглядный, структурированный вид редактируемых файлов. Однако совершенно точно он потребует и больше внимательности при наполнении публикуемых файлов.
Как быть со списками?
Теоретически может случиться ситуация, когда одновременный хотфикс с другим релизом нарушит структуру списка или таблицы. Рассмотрим теоретический пример со списком (с таблицей подход будет аналогичным). Сперва обозначим исходные данные и условия.
Исходные данные. Представим ситуацию, когда список хотфикса 1.1.1 разрывает список релиза 1.3.0.

Примечание: к сожалению, директива include не работает со списками и таблицами. Поэтому придётся дублировать контент.
Соберём документацию только для хотфикса 1.1.1:
Шаг 1. Наполняем исходный файл комментариями в соответствии с потребностями публикации хотфикса 1.1.1.

Шаг 2. Наполняем тестируемый публикуемый файл директивой для сборки актуального контента.

Шаг 3. Публикуем. Убеждаемся, что результат соответствует ожиданиям.

Именование коммитов
Архитектура подразумевает большое количество коммитов в единой ветке, поэтому рекомендуем именовать коммиты максимально полно. Например:
DAPP-5508 K8SC-1.6.1 Admin del Harbor v 1.04
Тут есть:
-
Номер задачи;
-
Код продукта или компонента и через дефис — его версия заглавными буквами (K8S-2.1.3);
-
Имя изменяемого документа с заглавной буквы (Operator, PMI, ReleaseNote). Не указывайте имя документа, если изменяете несколько файлов, например config-файлы по соответствующей задаче.
-
Краткое, но ёмкое и понятное отображение внесенных изменений:
-
в случае добавления используйте
add; -
в случае удаления используйте
del; -
для описания используйте
description; -
для изменения и редактирования используйте:
-
changeдля замены (change Version); -
correctдля правки грамматических и синтаксических ошибок; -
editдля лексических, морфологических и косметических правок — редактирование списков, названия разделов и т. д.; -
fixдля исправления кода.
-
-
пример:
add description Envoy.
-
-
Версия изменения для отображения последовательности в рамках одного pull request и одного изменения (v 1.24).
Теперь легко будет найти любой коммит и понять, какие изменения вносились.
Заключение
С новой архитектурой ведения Git время подготовки документации значительно сократилось, а её выпуск стал удобнее. Подытожим по пунктам, к чему мы пришли:
-
Ведение изменений и актуальная информация в единой ветке. Это исключает «лишние» ветки по каждой задаче. При этом сохраняется возможность создания дополнительных веток task-branch-N.
Отказ от создания избыточной task-branch-N экономит от 10 минут при минимальном изменении контента (например, редактуре нескольких слов) до нескольких часов при крупных изменениях. Мы отказались от создания примерно 50-70% лишних веток и pull request’ов.
-
Полный diff в PR для проверяющего на протяжении всего релиза. Единый pull request позволяет просматривать все изменения на протяжении релизного цикла. Больше не нужно регулярно делать compare для сверки — проверяющий может отслеживать изменения в одном окне. Первые проверяющие уже отметили удобство единого pull request. Удобно также отслеживать и собственные ошибки.
-
Уменьшение количества конфликтов из-за «перекрестного» выполнения задач примерно на 80%, даже при одновременной работе трёх специалистов в единой ветке. Это значительный прорыв в качестве и скорости подготовки документации.
-
Гибкое регулирование дополнительных веток и PR. Ведущий технический писатель может сам управлять ими, при необходимости создавая отдельную ветку — например, чтобы показать разработчику новый контент для валидации.
-
Отказ от создания новой ветки при изменении контента типа «Удаление». Просто удалите ненужное, и это отразится в едином pull request. Проверяющий сможет просмотреть изменения в удобное ему время.
-
Экономия времени на согласованиях и проверках. Мы отказались от регулярных проверок бесчисленного количества pull requests. Проверка единого pull request сэкономила нам примерно 30% времени.
Надеемся, что наш опыт поможет и вам упростить и ускорить работу с документированием. Спасибо за внимание!
Автор: KApT

