# Git Tag: разметка релизов и закладки в истории

Индекс LLMS: [llms.txt](/llms.txt)

---

## Git Tag: разметка релизов и закладки в истории

Теги — это механизм Git для присвоения осмысленных меток конкретным коммитам. В отличие от веток, теги не двигаются: они зафиксированы в точке коммита и служат якорями для релизов, версий и важных контрольных точек. Без тегов релизная история превращается в поиск по хешам — и это прямой путь к ошибкам деплоя.

---

## Типы тегов: lightweight vs annotated

Существует два типа тегов. Lightweight — это просто имя, привязанное к коммиту, без дополнительных метаданных. Annotated — полноценный объект Git с автором, датой, сообщением и возможностью подписи.

> [!WARNING]
> Для релизов всегда используйте annotated теги. Lightweight не содержат метаданных и не подписываются — при аудите или откате вы потеряете контекст.

| Свойство | Lightweight | Annotated |
|---|---|---|
| Объект в базе | Нет | Да (объект tag) |
| Сообщение | Нет | Да |
| Автор/дата | Нет | Да |
| GPG-подпись | Нет | Да |
| Скорость создания | Быстрее | Чуть медленнее |

---

## Создание, просмотр и удаление тегов

Создание annotated тега:

```bash
git tag -a v1.2.0 -m "Релиз 1.2.0: стабилизация API"
```

Создание lightweight тега:

```bash
git tag v1.2.0-rc1
```

Просмотр всех тегов:

```bash
git tag
```

Просмотр деталей конкретного annotated тега:

```bash
git show v1.2.0
```

Удаление локального тега:

```bash
git tag -d v1.2.0-rc1
```

Список тегов по шаблону:

```bash
git tag -l "v1.*"
```

> [!TIP]
> Флаг `-l` поддерживает glob-шаблоны. Это быстрее, чем гонять `grep` по выводу `git tag`.

---

## Отправка тегов в remote

По умолчанию `git push` **не** отправляет теги. Это частая причина того, что коллеги не видят релизный тег на удалённом репозитории.

Отправка одного тега:

```bash
git push origin v1.2.0
```

Отправка всех локальных тегов:

```bash
git push origin --tags
```

Удаление тега на remote:

```bash
git push origin --delete v1.2.0
```

Локальное удаление и удаление на remote — это две разные операции. Забыть выполнить вторую — типичная ошибка при откате релиза.

---

## Подписание тегов GPG

Annotated теги можно подписать GPG-ключом. Это гарантирует, что тег был создан конкретным автором и не был подменён.

Предварительно убедитесь, что GPG-ключ настроен:

```bash
gpg --list-secret-keys --keyid-format=long
git config --global user.signingkey <KEY_ID>
git config --global gpg.format openpgp
```

Создание подписанного тега:

```bash
git tag -s v1.2.0 -m "Подписанный релиз 1.2.0"
```

Проверка подписи:

```bash
git tag -v v1.2.0
```

> [!NOTE]
> Если `git tag -v` выдаёт ошибку «no signature found», тег не подписан. Если «Good signature from...» — подпись валидна. Убедитесь, что публичный ключ автора доступен в вашем keyring.

---

## Работа с тегами в CI/CD пайплайнах

В пайплайнах теги — основной триггер для релизов. Большинство систем CI/CD позволяют фильтровать ветки и теги.

Пример для GitHub Actions:

```yaml
on:
  push:
    tags:
      - 'v*'

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-tags: true
      - run: echo "Сборка для $(git describe --tags)"
```

Пример для GitLab CI:

```yaml
deploy:
  script:
    - echo "Деплой тега $CI_COMMIT_TAG"
  rules:
    - if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/'
```

Полезные команды для использования внутри пайплайна:

```bash
# Текущий тег, если коммит помечен
git describe --tags --exact-match HEAD

# Последний тег до текущего коммита
git describe --tags --abbrev=0 HEAD

# Все теги, отсортированные по дате создания
git tag --sort=-creatordate
```

> [!TIP]
> Всегда используйте `fetch-tags: true` в шаге checkout. Без этого пайплайн может не увидеть теги и сломаться фильтр по `$CI_COMMIT_TAG`.

---

Теги — минимальный инструмент с максимальным эффектом. Annotated с подписями GPG, отправка `--tags` при релизе, фильтрация по паттерну `v*` в CI — этого набора достаточно, чтобы релизная история оставалась читаемой и проверяемой.
Задача: написать IT-заметку для блога Lead DevOps на тему Git Tag. Формат: markdown тело
