Теги версий version tags в Git и Docker

17 декабря 2025
Автор

Олег Марков

Введение

Теги версий (version tags) — это способ привязать понятную человеку метку к определенному состоянию кода, артефакта сборки или контейнера. Они помогают ответить на вопросы вида:

  • Какая версия сейчас в продакшене
  • На основе какого коммита собран этот образ
  • Где находится стабильная версия, а где — экспериментальная

Смотрите, я покажу вам, как теги версий упрощают жизнь в нескольких типичных сценариях:

  • вы используете Git и хотите зафиксировать релиз 1.0.0;
  • вы публикуете Docker-образы и должны поддерживать latest, stable и конкретные версии;
  • вы настраиваете CI/CD и вам нужно однозначно помечать релизные сборки.

Давайте разберем, что такое теги версий, как их правильно придумывать, где хранить и как сделать так, чтобы они действительно помогали, а не путали команду.


Что такое тег версии

Основное определение

Тег версии — это текстовая метка, которую вы присваиваете:

  • коммиту в системе контроля версий (чаще всего в Git);
  • артефакту сборки (например, архиву с бинарником);
  • образу контейнера (например, Docker image);
  • пакету в репозитории (npm, PyPI, Maven, Go Module и т.д.).

Главная идея — связать человеческое представление о версии с конкретным техническим артефактом. Вместо «коммит 7f9d2e3» вы говорите «версия 1.4.2».

Чаще всего в тегах версий используется семантическое версионирование: формат MAJOR.MINOR.PATCH (например, 2.5.1). Но на практике применяют и другие схемы — с датами, суффиксами среды (-dev, -prod), хешами, build-номерами.


Семантическое версионирование как основа тегов

Что такое семантическое версионирование

Семантическое версионирование (SemVer) — это договоренность, как читать номер версии и что он означает. В классическом виде:

  • MAJOR — мажорная версия (несовместимые изменения);
  • MINOR — минорная (новые возможности, совместимые по API);
  • PATCH — патч-версия (исправления ошибок, без изменения контракта).

Например, версия 3.2.7 содержит:

  • 3 — третье поколение API, может быть несовместимо с 2.x.x;
  • 2 — в этой мажорной ветке уже был добавлен второй пакет изменений;
  • 7 — это седьмой набор исправлений к версии 3.2.0.

Когда увеличивать какую часть версии

Давайте разберемся на примере типичных изменений:

  • Изменили формат запроса в API, удалили поле, поломали обратную совместимость:

    • увеличиваем MAJOR: 1.4.5 → 2.0.0.
  • Добавили новое поле в ответ API, которое не ломает существующих клиентов:

    • увеличиваем MINOR: 1.4.5 → 1.5.0.
  • Исправили баг, не меняя контракта, добавили логирование:

    • увеличиваем PATCH: 1.4.5 → 1.4.6.

Семантическое версионирование удобно тем, что по номеру версии уже можно примерно понять, насколько опасен апдейт.


Теги версий в Git

Зачем тегировать коммиты

Если вы используете Git, теги — стандартный механизм пометить конкретный коммит как релизную версию. Это нужно:

  • чтобы можно было быстро вернуться к коду релиза 1.2.0;
  • чтобы CI/CD понимал, какие коммиты — релизные;
  • чтобы автоматически собирать changelog между версиями;
  • чтобы при расследовании инцидента знать, какой именно код был в продакшене.

Виды Git-тегов

В Git есть два типа тегов:

  • lightweight tag (легковесный) — просто указатель на коммит;
  • annotated tag (аннотированный) — тег с метаданными: автор, дата, сообщение, подписи.

Пример создания легковесного тега

# Помечаем текущий коммит тегом версии 1.0.0
git tag v1.0.0

Здесь мы создаем тег без дополнительной информации. Такой формат подходит для простых локальных пометок, но хуже для релизов.

Пример создания аннотированного тега

# Создаем аннотированный тег с сообщением
git tag -a v1.0.0 -m "Релиз первой стабильной версии"
# Просмотр информации о теге и связанном коммите
git show v1.0.0

Комментарии в этом примере подсказывают вам, какие команды использовать в реальной работе.

Рекомендация: для релизных тегов используйте именно аннотированные теги. Они лучше документируют историю и могут быть подписаны GPG.

Как назначать теги на разные коммиты

Иногда вам нужно создать тег не на текущий коммит, а на один из прошлых. Давайте посмотрим, как это сделать.

# Создаем тег на конкретный коммит по его хешу
git tag -a v1.1.0 7f9d2e3 -m "Релиз 1.1.0 на основе коммита 7f9d2e3"

Если вы не уверены в нужном хеше, можно сначала посмотреть лог:

# Показываем сокращенную историю коммитов
git log --oneline --decorate --graph --all

Здесь вы увидите коммиты и уже существующие теги, что упростит навигацию.

Работа с удаленными тегами

Локального тега мало — его нужно отправить в удаленный репозиторий, чтобы его видела вся команда и CI/CD.

# Отправить один тег на удаленный репозиторий origin
git push origin v1.0.0

# Отправить все локальные теги сразу
git push origin --tags

Если понадобится удалить тег:

# Удаляем тег локально
git tag -d v1.0.0

# Удаляем тег в удаленном репозитории
git push origin :refs/tags/v1.0.0

Обратите внимание, что удаление тегов, на которые кто-то ссылается в документации или скриптах сборки, может привести к путанице. Старайтесь удалять только те теги, которые были созданы по ошибке.


Теги версий в Docker

Зачем тегировать Docker-образы

Docker-образы часто используют несколько тегов для одного и того же образа. Это позволяет:

  • иметь стабильный тег latest для последней версии;
  • иметь тег с конкретной версией, например 1.3.0;
  • иметь тег, привязанный к конкретному коммиту или сборке, например 1.3.0-7f9d2e3.

Теги помогают вам понять, какой именно образ сейчас крутится в кластере, и упростить откат.

Базовые операции с тегами Docker

Теперь вы увидите, как это выглядит в коде командной строки.

# Собираем образ и даем ему тег myapp:1.0.0
docker build -t myapp:1.0.0 .

# Публикуем образ в Docker Registry
docker push myapp:1.0.0

# Создаем дополнительный тег latest для того же образа
docker tag myapp:1.0.0 myapp:latest

# Публикуем тег latest
docker push myapp:latest

Комментарии рядом с командами подсказывают, что именно происходит на каждом шаге.

Фактически Docker тег — это просто человекочитаемый алиас к одному и тому же image ID. Один образ может иметь несколько тегов.

Схемы тегирования Docker-образов

Давайте разберемся на примере нескольких распространенных схем.

Схема 1: только семантическая версия

  • myapp:1.0.0
  • myapp:1.0.1

Плюсы:

  • просто и понятно;
  • легко связать версию образа с версией кода.

Минусы:

  • вы не видите, какой именно коммит был собран;
  • при пересборке «той же» версии будет трудно отличить старую и новую сборки.

Схема 2: версия + commit hash

  • myapp:1.0.0-7f9d2e3
  • myapp:1.0.1-a8c1f45

Покажу вам, как это реализовано на практике с помощью аргумента сборки:

# Строим образ и добавляем в тег версию и хеш коммита
# Предполагаем, что переменные VERSION и GIT_SHA определены заранее
docker build -t myapp:${VERSION}-${GIT_SHA} .

# Пример значений
# VERSION=1.0.0
# GIT_SHA=7f9d2e3

Такая схема дает более точную привязку образа к состоянию репозитория.

Схема 3: stable, latest и окружения

Дополнительно к версионным тегам можно ввести логические:

  • myapp:latest — последняя собранная версия;
  • myapp:stable — последняя проверенная и одобренная версия;
  • myapp:prod, myapp:staging — образы, которые использует конкретное окружение.

Например:

# Помечаем текущую стабильную версию тегами stable и prod
docker tag myapp:1.2.3 myapp:stable
docker tag myapp:1.2.3 myapp:prod

docker push myapp:stable
docker push myapp:prod

Обратите внимание, что такие теги — это всегда указатели. Их можно перепривязывать к новым версиям, не меняя манифестов деплоя (если там используются логические теги).


Связь Git-тегов и Docker-тегов

Зачем связывать Git и Docker

Если вы помечаете в Git релиз тегом v1.2.3 и затем собираете Docker-образ с тегом 1.2.3, вы получаете прозрачную линию:

Git tag → CI сборка → Docker image tag → продакшен.

Это упрощает:

  • поиск кода, который сейчас крутится;
  • анализ регрессий;
  • аудит релизов.

Пример простого пайплайна

Давайте разберемся на примере упрощенного сценария:

  1. Вы создаете в Git тег v1.2.3.
  2. CI запускает сборку при появлении тега.
  3. CI собирает Docker-образ и помечает его тегами:
    • myapp:1.2.3
    • myapp:1.2.3-<short_sha>
    • myapp:stable (по решению)

Ниже приведен псевдокод для CI-конвейера (синтаксис близок к GitLab CI):

# Джоб, который запускается только при пуше тега
build_and_push:
  stage: build
  # Здесь мы говорим, что задача запускается при пуше тегов
  only:
    - tags
  script:
    # Извлекаем версию из имени тега, например v1.2.3 -> 1.2.3
    - VERSION=${CI_COMMIT_TAG#v}

    # Собираем образ с тегом версии
    - docker build -t registry.example.com/myapp:${VERSION} .

    # Добавляем тег с сокращенным хешем коммита
    - docker tag registry.example.com/myapp:${VERSION} \
        registry.example.com/myapp:${VERSION}-${CI_COMMIT_SHORT_SHA}

    # Публикуем оба тега
    - docker push registry.example.com/myapp:${VERSION}
    - docker push registry.example.com/myapp:${VERSION}-${CI_COMMIT_SHORT_SHA}

Комментарии помогают вам увидеть, где именно извлекается версия и как формируются теги.


Стратегии тегирования в проектах

Базовая стратегия для небольших проектов

Если у вас небольшой сервис или библиотека, можно начать с простой схемы:

  • В Git:
    • использовать аннотированные теги вида vMAJOR.MINOR.PATCH;
  • В Docker:
    • собирать образы с тегом MAJOR.MINOR.PATCH;
    • при необходимости добавлять latest для последней версии.

Пример:

  • Git: v1.0.0
  • Docker: myapp:1.0.0, myapp:latest

При релизе 1.1.0:

  • Git: v1.1.0
  • Docker: myapp:1.1.0, myapp:latest

Стратегия для микросервисной архитектуры

Когда сервисов много, теги версий особенно важны. Здесь полезно:

  • строго соблюдать SemVer;
  • для каждого сервиса иметь свой набор тегов;
  • в Kubernetes-манифестах использовать «неподвижные» теги с версией, а не latest.

Например, деплой манифеста:

# Фрагмент Deployment для Kubernetes
spec:
  template:
    spec:
      containers:
        - name: myapp
          # Здесь мы используем конкретный тег версии
          image: registry.example.com/myapp:1.4.2

Комментарий к полю image подчеркивает, что мы избегаем latest, чтобы деплой был детерминированным.

После тестирования вы можете обновить этот тег на новый:

image: registry.example.com/myapp:1.5.0

Это позволяет четко отследить, на какой версии произошла проблема.


Работа с тегами версий в пакетных менеджерах

npm (JavaScript, Node.js)

В экосистеме Node.js версия пакета задается в файле package.json. Тег в Git часто синхронизируют с этой версией.

Фрагмент package.json:

{
  "name": "my-lib",
  "version": "1.2.3"
}
# Публикуем пакет в npm с указанной версией
npm publish

Когда вы повышаете версию:

# Автоматически увеличиваем patch-версию и создаем Git-тег
npm version patch
# Автоматически увеличиваем minor-версию
npm version minor
# Автоматически увеличиваем major-версию
npm version major

Каждая команда:

  • обновляет поле version в package.json;
  • создает коммит;
  • создает соответствующий Git-тег (например, v1.2.4).

Здесь вы видите, как инструмент сам поддерживает связь между кодом и тегом.

PyPI (Python)

В Python версия обычно задается в pyproject.toml или setup.cfg. Соглашения похожие: версия пакета = тег в Git.

Фрагмент pyproject.toml:

[project]
name = "my-lib"
version = "0.3.1"

Часто используют инструменты вроде setuptools_scm, которые автоматически берут версию из Git-тегов. Это еще сильнее привязывает понятие «версии» к тегам.


Автоматизация тегирования в CI/CD

Автоинкремент версий

Давайте посмотрим, как можно автоматически увеличивать номер версии на основе изменений.

Идея:

  • анализировать сообщения коммитов;
  • по ключевым словам решать, что увеличивать (MAJOR, MINOR, PATCH);
  • генерировать новый тег версии.

Например, принятое соглашение по commit messages:

  • feat: — новая функциональность (MINOR);
  • fix: — исправление (PATCH);
  • BREAKING CHANGE в описании — MAJOR.

Специализированные инструменты (например, semantic-release) позволяют:

  • прочитать историю коммитов после последнего тега;
  • вычислить новую версию;
  • создать Git-тег;
  • опубликовать релиз и артефакты.

Использование build-номеров

Иногда к версиям добавляют build-номер:

  • 1.2.3+45
  • 1.2.3-build.45

Это удобно, когда:

  • у вас бывают несколько сборок одной версии (например, инженеры тестируют разные варианты);
  • нужно связать релиз с конкретной сборкой CI.

Пример формирования версии в CI (псевдокод):

# Берем базовую версию из файла
BASE_VERSION=$(cat VERSION)

# Используем номер пайплайна CI как build-номер
BUILD_NUM=${CI_PIPELINE_ID}

# Формируем полную версию
FULL_VERSION="${BASE_VERSION}+${BUILD_NUM}"

echo "Полная версия сборки: ${FULL_VERSION}"

Комментарий в выводе подсказывает, как выглядит итоговая версия.


Хорошие практики работы с тегами версий

1. Не переиспользовать теги

Если вы уже выпустили версию 1.0.0 и кто-то ее использует, не стоит:

  • пересобирать код;
  • заново пушить тег 1.0.0 на другой коммит.

Это может привести к ситуациям, когда под одной и той же версией понимаются разные состояния. Лучше:

  • выпускать 1.0.1;
  • или использовать дополнительный суффикс (1.0.0-1, 1.0.0-hotfix).

2. Фиксировать версию в коде и документации

Хорошая практика — хранить версию не только в тегах, но и в коде:

  • в константе (для сервисов);
  • в файле VERSION;
  • в package.json, pyproject.toml и аналогичных файлах.

Тогда сервис может, например, отображать версию в /health или /version эндпоинтах, а вы сможете быстро сравнить:

  • версию тега;
  • версию Docker-образа;
  • версию, возвращаемую сервисом.

3. Единый формат именования

Старайтесь не смешивать форматы:

  • v1.2.3 и 1.2.3;
  • release-1.2.3 и 1.2.3.

Выберите один формат, например vMAJOR.MINOR.PATCH для Git и MAJOR.MINOR.PATCH для Docker, и придерживайтесь его.

Это снизит риск ошибок в скриптах и пайплайнах, где вы парсите версию.

4. Логические теги использовать аккуратно

Теги вроде latest, stable, prod удобны, но:

  • они «плавающие» — сегодня указывают на одну версию, завтра на другую;
  • трудно восстановить историю, если вы не ведете дополнительный журнал.

Хороший компромисс:

  • в продакшене использовать зафиксированные теги (1.3.0);
  • логические теги применять в тестовых и временных окружениях;
  • обязательно логировать, каким именно тегом был развернут релиз.

Типичные ошибки и как их избежать

Ошибка 1. Использование latest в продакшене

Если вы в деплое указываете:

image: myapp:latest

то каждый новый push latest может незаметно менять поведение продакшена. Это усложняет отладку и откаты.

Решение:

  • в продакшене использовать только конкретные версии: 1.2.3;
  • latest использовать только локально или в тестовых окружениях.

Ошибка 2. Беспорядочные версии

Когда разработчики ставят версии «на глаз»:

  • 1.0, 1.1, 1.1.1, 1.1.1fix;
  • 2023.01, 2023.1.2-prod.

Это затрудняет анализ и автоматизацию. Рекомендация:

  • выбрать одну договоренность (SemVer или дата+build);
  • документировать ее в CONTRIBUTING или README;
  • на CI проверять корректность формата версии.

Ошибка 3. Отсутствие связи между тегом и изменениями

Если вы создаете тег 1.2.3, но нигде не описываете, что в него вошло, поддерживать проект становится сложно.

Решение:

  • вести CHANGELOG (вручную или автоматически);
  • в Git-теге оставлять понятное описание релиза;
  • использовать релизные заметки в GitHub, GitLab и т.п.

Заключение

Теги версий — это базовый, но очень важный инструмент управления жизненным циклом программного обеспечения. Они связывают:

  • код (Git-коммиты);
  • артефакты сборки (пакеты, бинарники);
  • окружения (Docker-образы, деплои).

При продуманной схеме тегирования вы всегда можете ответить:

  • какой код сейчас в продакшене;
  • какие изменения были между 1.2.0 и 1.3.0;
  • к какому коммиту относится конкретный образ.

Ключевые элементы:

  • использовать понятную схему версий (чаще всего SemVer);
  • обязательно тегировать релизы в Git;
  • синхронизировать Git-теги с тегами Docker и пакетных менеджеров;
  • автоматизировать создание и проверку тегов в CI/CD.

Чем раньше вы введете в проекте ясные правила тегирования версий, тем проще будет масштабировать разработку, сопровождение и деплой.


Частозадаваемые технические вопросы

1. Как получить последнюю версию по тегам в Git из скрипта

Можно отсортировать теги по версии и взять последний:

# Выводим последний тег по сортировке версий
git describe --tags --abbrev=0

Если вам нужна сортировка по семантическим версиям, а теги записаны в формате vMAJOR.MINOR.PATCH, можно использовать:

# Получаем последний тег в формате vX.Y.Z
git tag --list "v*" --sort=-version:refname | head -n 1

Комментарии здесь не нужны, команда и так читается достаточно явно.

2. Как проверить в CI, что тег версии соответствует формату SemVer

Вы можете использовать простое регулярное выражение:

# Проверяем, что тег выглядит как vX.Y.Z
echo "${CI_COMMIT_TAG}" | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+$'

Если команда grep вернет ненулевой код выхода, значит тег не соответствует формату, и можно прервать пайплайн.

3. Как автоматически проставлять Docker-теги с датой сборки

В скрипте сборки можно добавить дату:

# Формируем тег вида 1.2.3-20251204
DATE_TAG=$(date +%Y%m%d)
VERSION=1.2.3
docker build -t myapp:${VERSION}-${DATE_TAG} .

Такой тег поможет быстро понять, когда был собран образ.

4. Как связать версию из файла и Git-тег в проверке

Частая задача — убедиться, что версия из файла совпадает с Git-тегом. Можно сделать так:

# Читаем версию из файла VERSION
FILE_VERSION=$(cat VERSION)

# Удаляем префикс v из тега
TAG_VERSION=${CI_COMMIT_TAG#v}

test "${FILE_VERSION}" = "${TAG_VERSION}"

Если сравнение не пройдет, пайплайн можно остановить, чтобы не выпускать «ломаный» релиз.

5. Как пометить hotfix к старой версии без нарушения SemVer

Если вам нужно выпустить фикc для старой ветки, увеличивайте PATCH в рамках этой ветки:

  • было 1.4.2 (старая ветка);
  • основная ветка уже ушла на 2.x;
  • hotfix — это 1.4.3.

Git-тег будет v1.4.3, Docker-тег — 1.4.3. Такой подход сохраняет прозрачность версий и не ломает SemVer.

Ветка релиза в Git - как организовать стабильные релизы без хаосаСтрелочка вправо

Постройте личный план изучения Git до уровня Middle — бесплатно!

Git — часть карты развития Frontend

  • step100+ шагов развития
  • lessons30 бесплатных лекций
  • lessons300 бонусных рублей на счет

Бесплатные лекции

Все гайды по Git

Открыть базу знаний

Лучшие курсы по теме

изображение курса

Основы Git

Антон Ларичев
AI-тренажеры
Гарантия
Бонусы
иконка звёздочки рейтинга4.9
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

TypeScript с нуля

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Next.js - с нуля

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее

Отправить комментарий