Олег Марков
Отправка тегов на сервер git push --tags
Введение
Работа с тегами в Git часто кажется второстепенной задачей по сравнению с ветками и коммитами. Но именно теги помогают фиксировать важные точки в истории проекта – релизы, стабильные версии, экспериментальные сборки. Когда вы начинаете работать в команде и использовать удаленные репозитории, встает практический вопрос: как отправить все локальные теги на сервер, чтобы остальные участники могли их увидеть и использовать.
Здесь на сцену выходит команда git push --tags. Смотрите, я покажу вам, как она работает, какие у нее подводные камни и когда лучше выбрать более точечные команды, а не слепо отправлять все подряд.
В статье вы разберетесь:
- какие бывают теги в Git и чем они отличаются;
- что именно делает
git push --tagsи зачем он нужен; - как отправлять теги выборочно;
- как удалять или переопределять теги на сервере;
- как встроить работу с тегами в процесс релизов.
Что такое теги в Git и зачем их отправлять на сервер
Зачем вообще нужны теги
Тег в Git – это "ярлык", который указывает на конкретный коммит. В отличие от веток, теги не двигаются вперед при новых коммитах, а навсегда "приклеены" к одной точке истории.
На практике теги чаще всего используют для:
- пометки релизов –
v1.0.0,v2.3.5и т.п.; - фиксации критичных состояний –
before-migration,stable-2024-01; - совместной работы с CI/CD – запуск сборки или деплоя по тегу;
- воспроизведения конкретного состояния проекта.
Чтобы этим тегом могли пользоваться другие разработчики или автоматизированные системы (CI, деплой-сервера), его нужно отправить в удаленный репозиторий – на GitHub, GitLab, Bitbucket или ваш корпоративный сервер.
Типы тегов – аннотированные и легковесные
Git поддерживает два основных типа тегов. Давайте разберемся, в чем разница, потому что это важно для понимания, какие теги вы отправляете на сервер.
Легковесный тег (lightweight tag)
Это просто имя, указывающее на коммит. Никакой дополнительной информации.
Создание:
# Создаем легковесный тег v1.0.0 для текущего коммита
git tag v1.0.0
Особенности:
- не содержит автора, даты, сообщения;
- по сути – это просто ссылка на hash коммита;
- создается быстро, но мало метаданных.
Аннотированный тег (annotated tag)
Это полноценный объект в базе Git. Он хранит:
- имя тега;
- ссылку на коммит;
- автора тега;
- дату;
- сообщение (аннотацию);
- опционально – подпись GPG.
Создание:
# Создаем аннотированный тег с сообщением
git tag -a v1.0.0 -m "Первый стабильный релиз"
Комментарий к команде:
# -a - создаем аннотированный тег
# v1.0.0 - имя тега
# -m "..." - сообщение тега, хранится в Git как описание
В большинстве командных процессов для релизов используют именно аннотированные теги. Они информативнее и лучше интегрируются с инструментами релизов и подписи релизов.
Почему git push не отправляет теги по умолчанию
Важный момент: когда вы делаете обычный git push, Git отправляет коммиты и обновления веток, но не все ваши теги.
Стандартный git push:
git push origin main
Отправляет:
- все новые коммиты, которые появились в ветке
main; - обновляет указатель ветки
mainна сервере.
Но локально созданные теги останутся только у вас, пока вы явно не отправите их в удаленный репозиторий.
Здесь и появляется потребность в командах вида:
git push origin <tagname>– отправить один тег;git push origin --tags– отправить все локальные теги, которых нет на сервере.
Давайте теперь разберем, как именно работает git push --tags.
Как работает git push --tags
Базовый синтаксис и поведение
Команда:
git push --tags
по умолчанию эквивалентна:
git push origin --tags
если у вас настроен удаленный репозиторий origin и он используется по умолчанию.
Что делает эта команда:
- находит все локальные теги, которые существуют в вашем репозитории;
- сверяет их с тегами в удаленном репозитории;
- отправляет те теги, которых еще нет на сервере;
- не удаляет и не изменяет уже существующие теги на сервере.
Обратите внимание: git push --tags не перезаписывает теги в удаленном репозитории, если там уже есть тег с таким именем. Если локальный тег и удаленный тег с тем же именем указывают на разные коммиты, Git обычно откажется "тихо" их перезаписать, потребуется явная перезапись.
Пример с несколькими тегами
Давайте разберемся на примере небольшой истории:
# Создаем несколько аннотированных тегов
git tag -a v1.0.0 -m "Релиз 1.0.0"
git tag -a v1.1.0 -m "Релиз 1.1.0"
git tag -a v2.0.0-rc1 -m "Release candidate 2.0.0"
# Отправляем коммиты в основную ветку
git push origin main
# Теперь отправляем все теги разом
git push origin --tags
Комментарии:
# Первая команда создаст три аннотированных тега в вашей локальной репе
# git push origin main отправит только коммиты и обновит ветку main
# git push origin --tags отправит все локальные теги, которых еще нет в origin
После выполнения git push origin --tags все три тега появятся на сервере. В интерфейсе GitHub или GitLab вы увидите их в списке Releases или Tags (в зависимости от интеграции).
Взаимодействие с конфигурацией push.default
Параметр push.default в Git управляет тем, какие ветки отправляются при git push без указания имени ветки. На теги он не влияет напрямую.
Например:
git config --global push.default simple
Задаёт стратегию отправки веток, но теги все равно нужно отправлять отдельно:
git push
git push --tags
Если вы планируете постоянно отправлять и ветки, и теги, можно объединить:
git push && git push --tags
или использовать алиас.
Создание алиаса:
git config --global alias.pushtags "push --tags"
Теперь вы можете использовать:
git pushtags
как короткую команду для отправки всех тегов.
Что будет, если теги уже есть на сервере
Если вы повторно выполните:
git push origin --tags
Git просто проверит, что все теги уже есть в удаленном репозитории, и ничего нового не отправит. Ошибок не будет, команда отработает быстро.
Это означает, что команду git push --tags можно запускать безопасно несколько раз. Она не удалит существующие теги и не перепишет их.
Выборочная отправка тегов
Иногда вам не нужно отправлять вообще все теги. Например, у вас есть множество тестовых тегов, и вы хотите отправить только релизные. В этом случае git push --tags будет слишком грубым инструментом.
Отправка одного тега
Самая базовая команда:
# Отправляем один конкретный тег
git push origin v1.2.0
Комментарии:
# origin - имя удаленного репозитория
# v1.2.0 - имя тега, который должен существовать локально
Эта команда:
- отправит тег
v1.2.0в репозиторийorigin; - не затронет другие теги и ветки.
Отправка нескольких тегов по имени
Если нужно отправить несколько тегов сразу, но не все:
git push origin v1.0.0 v1.1.0 v2.0.0-rc1
Здесь вы явно перечисляете, какие теги должны уйти в удаленный репозиторий.
Комбинация веток и тегов
Git позволяет в одной команде отправить и ветки, и теги:
git push origin main v1.0.0 v1.1.0
Комментарии:
# Сначала будет отправлена ветка main
# Затем будут отправлены теги v1.0.0 и v1.1.0
Это удобно, если ваш релизный процесс выглядит так:
- Вы сделали коммиты в
main. - Пометили релиз тегом
v1.2.0. - Одной командой отправили и ветку, и тег.
Работа с шаблонами и выборкой тегов
Иногда удобнее оперировать группами тегов, а не перечислять их вручную. Например, у вас есть:
- теги релизов:
v1.0.0,v1.1.0,v2.0.0; - теги кандидатов в релиз:
v2.0.0-rc1,v2.0.0-rc2; - внутренние теги:
internal-test-1,internal-test-2.
Использование refspec для выборки тегов
git push позволяет использовать refspec – правило, описывающее, какие ссылки отправлять. Для тегов это может выглядеть так:
# Отправляем только теги, начинающиеся с v2.
git push origin 'refs/tags/v2.*:refs/tags/v2.*'
Комментарии:
# 'refs/tags/v2.*' - все теги, имя которых начинается с v2.
# :refs/tags/v2.* - куда их поместить на сервере (тот же путь)
# Кавычки нужны, чтобы оболочка не интерпретировала звездочку
Это более продвинутый сценарий, но он полезен, если вы хотите:
- отправлять только релизные теги;
- не трогать внутренние или экспериментальные теги.
Фильтрация тегов перед отправкой
Часто проще сначала посмотреть, какие теги у вас вообще есть.
Список всех тегов:
git tag
Список с фильтром:
# Все теги, начинающиеся с v1.
git tag -l "v1.*"
# Все теги, содержащие rc
git tag -l "*rc*"
Комментарии:
# -l "шаблон" - вывод тегов по шаблону
# Шаблон работает примерно как подстановка в shell
После того, как вы увидели нужные теги, можно отправить их выборочно:
git push origin v1.0.0 v1.1.0 v1.2.0
Удаление и переопределение тегов на сервере
git push --tags не удаляет и не переписывает теги на удаленном репозитории. Но иногда вам нужно:
- удалить ошибочный тег;
- переместить тег на другой коммит (например, вы ошиблись с релизом).
Здесь важно быть аккуратным, потому что переопределение тегов может сломать ожидания других разработчиков и CI-пайплайнов.
Удаление тега в локальном и удаленном репозитории
Предположим, вы создали тег v1.0.0 не на тот коммит. Для начала нужно удалить его локально:
# Удаляем тег локально
git tag -d v1.0.0
Комментарии:
# -d - удалить тег из локального репозитория
# Эта команда не трогает удаленный репозиторий
Теперь нужно удалить тот же тег на сервере. Смотрите, я покажу вам, как это сделать с помощью git push:
# Удаляем тег в удаленном репозитории
git push origin :refs/tags/v1.0.0
Комментарии:
# Слева от двоеточия пусто - это "источник" удаления
# Справа refs/tags/v1.0.0 - удаленный тег, который нужно удалить
# Фактически мы говорим "отправить пустоту в этот тег"
Более короткий синтаксис (поддерживается в современных Git):
git push origin --delete v1.0.0
Комментарии:
# origin - удаленный репозиторий
# --delete v1.0.0 - удалить тег v1.0.0 на сервере
Переопределение (перемещение) тега
Если тег уже есть на сервере и вы хотите, чтобы он указывал на другой коммит, простой git push --tags не поможет, потому что он не перезаписывает существующие теги.
Алгоритм:
- Удалить тег на сервере.
- Пересоздать тег локально на нужном коммите.
- Снова отправить тег.
Пример:
# 1. Удаляем тег локально
git tag -d v1.0.0
# 2. Создаем новый тег v1.0.0 на нужном коммите
git tag -a v1.0.0 <commit-hash> -m "Исправленный релиз 1.0.0"
# 3. Удаляем старый тег на сервере
git push origin --delete v1.0.0
# 4. Отправляем новый тег
git push origin v1.0.0
Комментарии к важным моментам:
# <commit-hash> - хеш коммита, на который должен указывать тег
# Сначала нужно удалить тег на сервере, иначе Git может отказаться его перезаписать
В некоторых командах используют принудительную отправку тегов с --force, но для тегов такой подход менее прозрачен. Я рекомендую явное удаление и пересоздание – так вы лучше контролируете изменения.
Особенности и подводные камни git push --tags
Опасность "засорить" репозиторий тегами
Если вы активно создаете временные или экспериментальные теги локально, команда git push --tags отправит и их тоже. В результате:
- удаленный репозиторий будет переполнен незначимыми тегами;
- другим разработчикам будет сложно ориентироваться в списке тегов;
- CI/релизные процессы могут случайно реагировать на лишние теги.
Чтобы избежать этого, лучше разделять:
- локальные рабочие теги (например, с префиксом
tmp-,experiment-); - "официальные" теги, которые действительно должны попасть на сервер.
И отправлять только нужные:
git push origin v1.2.0
или использовать шаблоны и выборочные команды.
Ситуация, когда тег указывает на коммит, которого нет на сервере
Интересный случай: вы создали тег на коммите, который еще не отправлен в удаленный репозиторий.
Например:
# Новый коммит, пока только локально
git commit -am "Новая фича"
# Тег на этом коммите
git tag -a v1.3.0 -m "Релиз 1.3.0"
# Отправляем только тег
git push origin v1.3.0
Что произойдет:
- Git отправит тег
v1.3.0; - автоматически отправит и коммит (и его родителей), на который указывает этот тег.
То есть при отправке тега Git всегда заботится о том, чтобы тег не "висел в воздухе" – соответствующий коммит тоже попадает на сервер.
Поэтому часто хватает одной команды:
git push origin v1.3.0
без отдельного git push origin main, если ваша цель – именно релиз по тегу.
Взаимодействие с ветками и зеркальным пушем
Иногда в проектах используют "зеркальный" пуш:
git push --mirror origin
Эта команда синхронизирует:
- все ветки;
- все теги;
- все ref’ы.
Важно понимать: --mirror может удалить теги и ветки в удаленном репозитории, если вы удалили их локально. Это уже намного более "опасный" режим, чем git push --tags.
Для обычного рабочего процесса, когда вы просто хотите отправить теги на сервер, лучше использовать именно:
git push origin --tags
или выборочные:
git push origin v1.4.0
Практические сценарии использования тегов и git push --tags
Типичный релизный процесс с тегами
Давайте посмотрим, как выглядит простой, но понятный процесс релиза с использованием тегов:
- Вы завершили разработку фич в ветке
main. - Все тесты прошли, код готов к релизу.
- Вы создаете аннотированный тег
v1.0.0. - Отправляете ветку и тег на сервер.
- CI-система по тегу собирает и деплоит релиз.
Пошагово в командах:
# 1. Убеждаемся, что локальная ветка main актуальна
git checkout main
git pull origin main
# 2. Делаем последний коммит, если нужно
git commit -am "Подготовка к релизу v1.0.0"
# 3. Создаем аннотированный тег
git tag -a v1.0.0 -m "Релиз версии 1.0.0"
# 4. Отправляем ветку и тег в origin
git push origin main
git push origin v1.0.0
Комментарии:
# Здесь мы явным образом отправляем только релизный тег v1.0.0
# git push origin --tags тоже бы сработал, но отправил бы все локальные теги
Массовая отправка исторических тегов
Представьте, что вы:
- долго работали с локальным репозиторием;
- отмечали релизы тегами только у себя;
- позже подключили удаленный репозиторий.
Теперь вы хотите "подтянуть" все исторические теги в origin.
В этом случае как раз удобно использовать:
git push origin --tags
Результат:
- все существующие локальные теги уйдут на сервер;
- история ваших релизов станет видна всей команде.
Если вы волнуетесь из-за временных тегов, имеет смысл:
- Посмотреть список тегов.
- Удалить заведомо лишние.
- Только потом сделать
git push origin --tags.
Пример:
# 1. Смотрим все теги
git tag
# 2. Удаляем временные теги
git tag -d tmp-experiment-1
git tag -d tmp-experiment-2
# 3. Отправляем оставшиеся теги
git push origin --tags
Интеграция с CI/CD по тегам
Во многих CI-системах (GitHub Actions, GitLab CI, Jenkins, etc.) можно настроить запуск задач при появлении нового тега.
Пример – файл .gitlab-ci.yml:
release-job:
stage: deploy
script:
- echo "Deploy по тегу"
- ./deploy.sh # Скрипт деплоя
only:
- tags # Запускать только при пуше тега
Комментарии:
# only: - tags - эта настройка говорит GitLab
# "запускать job, только когда появляется новый тег"
В таком процессе команда git push origin --tags может неожиданно запустить множество задач, если у вас накопилось много тегов, которые еще не были отправлены. Поэтому для CI лучше:
- использовать выборочный пуш тегов;
- или настраивать CI на работу только с тегами определенного вида (например,
v*).
Рекомендации по использованию git push --tags
Суммируя практику, давайте сформулируем несколько рекомендаций.
Когда удобно использовать git push --tags
- вы впервые подключили удаленный репозиторий к существующему проекту;
- вы мигрируете репозиторий и хотите перенести все теги;
- вы уверены, что все локальные теги "чистые" и нужны на сервере;
- вы один работаете с репозиторием и используете теги только для релизов.
В таких сценариях git push --tags экономит время и не создает проблем.
Когда лучше не использовать git push --tags
- в больших командах, где у разработчиков могут быть свои временные теги;
- если вы часто создаете локальные технические теги;
- если CI запускается на каждый новый тег.
В этих случаях безопаснее отправлять теги выборочно:
git push origin v3.0.0
или небольшими группами.
Локальная дисциплина именования тегов
Хорошая практика – договориться о формате тегов:
- релизы:
vX.Y.Z(например,v1.0.0); - кандидаты:
vX.Y.Z-rcN(например,v2.0.0-rc1); - горячие фиксы:
vX.Y.Z-hotfixN.
Тогда:
- можно смело отправлять все теги
v*в удаленный репозиторий; - а временные теги называть, например,
tmp-*,user-*и не пушить их.
Вы даже можете использовать шаблоны refspec, чтобы отправлять только релизные теги:
git push origin 'refs/tags/v*:refs/tags/v*'
Здесь вы явно говорите "отправить теги, имя которых начинается с v".
Заключение
Команда git push --tags решает понятную задачу – отправить все локальные теги в удаленный репозиторий. Она помогает:
- быстро синхронизировать историю релизов;
- перенести проект на новый сервер;
- сделать все ваши "ярлыки" на коммиты доступными команде и CI-системам.
Однако у нее есть особенности:
- по умолчанию отправляются все локальные теги, в том числе временные;
- команда не удаляет и не перезаписывает существующие теги на сервере;
- для тонкого контроля чаще используют выборочный пуш тегов.
Если вы понимаете различие между аннотированными и легковесными тегами, умеете удалять и переопределять теги в локальном и удаленном репозитории и осознанно используете git push --tags, работа с релизами и историей проекта становится более прозрачной и предсказуемой.
Частозадаваемые технические вопросы по теме и ответы
Как отправить только аннотированные теги и не отправлять легковесные
Прямой встроенной команды "push только аннотированные теги" в Git нет, но можно сделать это в два шага:
- Получить список аннотированных тегов:
git for-each-ref refs/tags --format="%(objecttype) %(refname:short)" | grep "^tag " | awk '{print $2}'
Комментарии:
# git for-each-ref ... - выводит все ссылки в refs/tags
# grep "^tag " - фильтрует только аннотированные теги
# awk '{print $2}' - берет только имя тега
- Отправить их:
git push origin $(<список-аннотированных-тегов>)
На практике проще изначально использовать аннотированные теги для релизов, а легковесные – как временные и не пушить их вообще.
Как посмотреть, какие теги еще не отправлены на сервер
Можно сравнить локальные и удаленные теги:
# Локальные теги
git tag > local-tags.txt
# Теги на сервере (после git fetch --tags)
git fetch origin --tags
git tag -l > remote-tags.txt
Дальше используйте утилиту diff:
# Какие теги есть локально, но нет на сервере
grep -Fxv -f remote-tags.txt local-tags.txt
Комментарии:
# git fetch origin --tags - подтягивает все теги с сервера, не меняя локальные
# grep -Fxv ... - выводит строки, которых нет во втором файле
Как запретить перезапись тегов на сервере другими разработчиками
На уровне Git-сервера обычно можно настроить "protected tags". Например, в GitLab:
- Зайдите в Settings – Repository – Protected tags.
- Укажите шаблон тегов, например
v*. - Разрешите их создание только определенным ролям и запретите перезапись.
На уровне "чистого" Git можно использовать update-хуки на сервере, которые будут отклонять попытки изменения уже существующих тегов.
Почему git push --tags не удаляет теги на сервере, которые я удалил локально
git push --tags только добавляет новые теги на сервер, но не синхронизирует удаление. Логика такая же, как и для веток без флага --prune. Чтобы удалить тег на сервере, нужно:
git tag -d v1.0.0 # удалить локально
git push origin --delete v1.0.0 # удалить на сервере
Или использовать refspec с удалением:
git push origin :refs/tags/v1.0.0
Как склонировать репозиторий сразу со всеми тегами
При обычном git clone теги тоже скачиваются, но лучше явно обновить их:
git clone <url> project
cd project
git fetch --tags
Комментарии:
# git clone по умолчанию забирает теги, связанные с загруженными коммитами
# git fetch --tags полезен, если позже были добавлены новые теги
Постройте личный план изучения Git до уровня Middle — бесплатно!
Git — часть карты развития Frontend
100+ шагов развития
30 бесплатных лекций
300 бонусных рублей на счет
Бесплатные лекции
Все гайды по Git
Лучшие курсы по теме

Основы Git
Антон Ларичев
TypeScript с нуля
Антон Ларичев