n1ro°
RU

Компьютеры · Инструкция

git push --follow-tags: когда использовать и чем он отличается от --tags

git push --follow-tags полезен в release‑процессе, когда ветку и связанный с ней annotated tag хочется публиковать.

Редакция N1RO · Проверено

Короткий ответ

git push --follow-tags отправляет с веткой недостающие annotated tags из её истории. Чем отличается от --tags, lightweight tags и как проверить push.

Что именно делает --follow-tags при push

Обычный `git push origin main` обновляет те refs, которые заданы refspec или настройками push. Теги сами по себе в этот набор не обязаны попадать. Опция `--follow-tags` расширяет такой push: Git рассматривает локальные annotated tags в `refs/tags`, которые отсутствуют на remote и указывают на commit-ish, достижимый из refs, уже отправляемых текущей командой. Это делает опцию удобной для релизов: вы публикуете ветку с новым релизным коммитом и связанный аннотированный тег, но не отправляете старые или посторонние теги без связи с этим push. В документации Git отдельно отмечается, что `--tags` имеет другое поведение — он добавляет к push все refs из `refs/tags`. Поэтому эти две опции нельзя считать синонимами. Если в репозитории много локальных тегов, разница становится особенно важной.

Совет: Перед первым использованием посмотрите `git tag -n` и `git show <tag>`: так вы убедитесь, что релизная метка действительно annotated, а не lightweight.

Как опубликовать ветку и релизный тег одной командой

  1. Создайте или проверьте annotated tag, например `git tag -a v2.4.0 -m "Release 2.4.0"`. Аннотированный тег хранит отдельный tag object с автором, датой и сообщением; именно такие теги учитывает `--follow-tags` по своему назначению.
  2. Убедитесь, что tagged commit входит в историю ветки, которую вы собираетесь отправить: `git merge-base --is-ancestor v2.4.0 main` должен завершиться успешно для обычного релизного сценария. Если тег указывает на несвязанную историю, `--follow-tags` не обязан его подхватывать.
  3. Сначала выполните `git push --dry-run --follow-tags origin main`, если ваша версия Git и сервер поддерживают ожидаемый dry-run вывод. Просмотрите список refs: там должна быть ветка и нужный тег, но не набор случайных локальных тегов.
  4. Выполните `git push --follow-tags origin main`. После успеха проверьте `git ls-remote --tags origin` или веб-интерфейс GitHub/GitLab и убедитесь, что тег появился на remote.
  5. Если такое поведение нужно всегда, можно включить `git config --global push.followTags true` или настройку только в конкретном репозитории. Для разовой отмены используйте явное поведение команды, а не полагайтесь на память о глобальной конфигурации.

Важно: Для CI/release лучше явно писать `--follow-tags` в скрипте, даже если у разработчика включён `push.followTags=true`. Скрипт тогда не зависит от локальной конфигурации агента.

--follow-tags, --tags и явный тег: в чём разница

  • git push --follow-tags origin main. main + подходящие annotated tags, достижимые из отправляемой истории. Обычный release push
  • git push --tags origin. Все локальные refs/tags. Осознанная синхронизация всех тегов
  • git push origin v2.4.0. Конкретно указанный тег. Нужен один тег и полный контроль
  • git push origin main. Ветку по refspec, без гарантии публикации тегов. Теги публикуются отдельным этапом

Почему lightweight tag может не отправиться с --follow-tags

Lightweight tag — это фактически ref, который прямо указывает на объект, без отдельного tag object. Annotated tag хранит дополнительный объект с метаданными и сообщением. Поведение `--follow-tags` в документации сформулировано именно для annotated tags, поэтому ожидать автоматической публикации каждой lightweight‑метки неправильно. Если команда релиза создала `git tag v2.4.0` без `-a`, а затем CI выполняет `git push --follow-tags`, ветка может уйти, а ожидаемый тег — нет. Исправление зависит от политики проекта: либо создавайте релизные теги как annotated, либо пушьте нужный тег явно `git push origin v2.4.0`. Не стоит заменять проблему на `git push --tags`, если репозиторий содержит локальные экспериментальные теги: такой push затронет гораздо более широкий набор refs.

Предупреждение: Если релиз уже опубликован без тега, безопаснее отправить конкретный проверенный тег явно, чем включать `--tags` ради одного отсутствующего ref.

Как встроить --follow-tags в GitHub Actions и другие CI

В CI важны две отдельные вещи: локально должен существовать тег, а токен должен иметь право записывать refs на remote. Многие checkout‑шаги используют ограниченную глубину истории или не загружают все теги, поэтому сначала проверьте фактическое состояние `git tag` в runner. Если workflow сам создаёт annotated tag после сборки, тогда проблема fetch глубины может не касаться нового тега, но права push всё равно нужны. Перед отправкой полезно вывести `git show-ref --tags` и `git log -1 --decorate`, чтобы журнал job объяснял, какой объект публикуется. Затем используйте явную команду `git push --follow-tags origin HEAD:<branch>` или конкретный branch refspec. Не храните секреты в remote URL в логах. И не забывайте, что защищённые ветки и правила tag protection на сервере могут отклонить push независимо от корректности локальной команды.

Проверка перед release push

  • Тег annotated: `git cat-file -t <tag>` показывает `tag`, а не только commit.
  • Tagged commit достижим из ветки, которая входит в текущий push.
  • Имя тега соответствует принятой в проекте схеме версий.
  • Dry-run не показывает неожиданные refs.
  • Remote и branch указаны явно в автоматизации.
  • На сервере нет правила защиты, запрещающего создание тега этим токеном.

Когда лучше не использовать --follow-tags

Если релизный процесс требует строгого двухэтапного контроля — сначала branch, затем отдельное подтверждение и публикация тега — автоматическое следование тегам может быть нежелательным. То же относится к монорепозиторию, где несколько независимых команд создают annotated tags в общей истории и правила публикации зависят не только от достижимости коммита. В таких случаях безопаснее пушить конкретный ref `refs/tags/<name>` после отдельной проверки. `--follow-tags` хорошо работает, когда семантика проста: опубликованная ветка несёт релизный коммит, а связанные с ней annotated tags должны последовать автоматически. Выбор команды должен отражать процесс релиза, а не быть способом «на всякий случай отправить теги».

Что учитывать

Lightweight tag — это фактически ref, который прямо указывает на объект, без отдельного tag object. Annotated tag хранит дополнительный объект с метаданными и сообщением. Поведение `--follow-tags` в документации сформулировано именно для annotated tags, поэтому ожидать автоматической публикации каждой lightweight‑метки неправильно. Если команда релиза создала `git tag v2.4.0` без `-a`, а затем CI выполняет `git push --follow-tags`, ветка может уйти, а ожидаемый тег — нет. Исправление зависит от…

Источники и проверка

Фактическая часть сверена по первичным источникам (в т.ч. git-push Documentation). Пример и формулировки — редакция N1RO на 2026-09-21.