Tutorial

Tags no Git: como usar o git tag e versionar releases

Atualizado: · Skillaria.Top

O git tag coloca um marcador permanente em um commit específico, normalmente para identificar um release, como v1.2.0. Uma tag anotada é criada com git tag -a v1.2.0 -m "mensagem", e as tags são enviadas ao servidor separadamente: git push origin v1.2.0 ou git push --tags.

git tag é um marcador com nome em um commit específico. Diferente de uma branch, a tag não se move com novos commits: daqui a um ano, v1.2.0 vai apontar para o mesmo snapshot do código. Por isso as tags são usadas para releases, e sistemas de CI/CD muitas vezes disparam o build e a publicação justamente quando surge uma tag.

Tags leves e anotadas

O Git tem dois tipos de tag, e a diferença importa.

Leve (lightweight)Anotada (annotated)
Criaçãogit tag v1.0.0git tag -a v1.0.0 -m "..."
O que éapenas um ponteiro para um commitum objeto próprio no banco do Git
Autor, data, mensagemnãosim
Assinatura GPG/SSHnãopossível (-s)
Considerada pelo git describe por padrãonãosim
Quando usarmarcadores pessoais temporáriosreleases e tudo o que é publicado

Para releases, use tags anotadas: elas registram quem lançou a versão e quando, e podem ser assinadas.

Como criar uma tag

No commit atual

git tag -a v1.2.0 -m "Release 1.2.0: exportação de relatórios, timeout da API corrigido"

Sem -m, o Git abre o editor para a mensagem — prático se você quiser escrever a lista de alterações.

Em um commit antigo

Esqueceu de criar a tag no release? Sem problema, a tag pode ser colocada em qualquer commit:

git log --oneline -5
# 7be41d0 feat: exportação de relatórios
# 1c02e8f fix: timeout das requisições
git tag -a v1.1.0 1c02e8f -m "Release 1.1.0"

Tag assinada

git tag -s v1.2.0 -m "Release 1.2.0"
git tag -v v1.2.0     # verificar a assinatura

É preciso ter uma chave GPG configurada (ou SSH com gpg.format=ssh). GitHub e GitLab mostram essas tags com a marca de verificação.

Como listar as tags

git tag                       # todas as tags em ordem alfabética
git tag -l "v1.*"             # por padrão
git tag -n                    # com a primeira linha da mensagem
git tag --sort=-v:refname     # por versão, as mais novas primeiro
git show v1.2.0               # dados da tag e do commit
git describe --tags           # tag mais próxima: v1.2.0-3-g7be41d0

Atenção à ordenação: por padrão v1.10.0 aparece antes de v1.9.0, porque as strings são comparadas caractere a caractere. A opção --sort=v:refname ordena como versões.

A saída do git describe se lê assim: três commits depois da tag v1.2.0, commit atual 7be41d0 (a letra g significa git). É uma fonte prática de número de versão para builds entre releases.

Como enviar uma tag para o servidor

O git push comum não envia tags — essa é a causa frequente da pergunta "por que a tag não aparece no GitHub".

git push origin v1.2.0        # uma tag
git push --tags               # todas as tags locais
git push --follow-tags        # commits + tags anotadas que apontam para eles

O --follow-tags é mais seguro que o --tags: ele não envia tags leves acidentais que você criou para si. Dá para ativá-lo por padrão: git config --global push.followTags true.

Para baixar as tags do servidor: git fetch --tags. O git fetch comum também traz as tags que apontam para os commits baixados.

Como excluir ou mover uma tag

Exclusão

git tag -d v1.2.0                     # localmente
git push origin --delete v1.2.0       # no servidor
# equivalente antigo: git push origin :refs/tags/v1.2.0

Mover a tag para outro commit

git tag -a -f v1.2.0 <novo-hash> -m "Release 1.2.0"
git push origin -f v1.2.0

Tecnicamente é possível, mas em projetos públicos não vale mover uma tag já publicada. Quem já baixou a tag não vai recebê-la atualizada automaticamente: o Git não sobrescreve tags locais existentes no fetch sem --force. No fim, "v1.2.0" será um código diferente para pessoas diferentes. O certo é lançar a v1.2.1.

Como saber quais commits entraram em um release

As tags são práticas como limites de intervalos em todos os comandos de leitura do histórico:

git log v1.1.0..v1.2.0 --oneline        # commits entre releases
git diff v1.1.0 v1.2.0 --stat           # quais arquivos mudaram
git tag --contains 1c02e8f              # em quais releases está este commit
git merge-base --is-ancestor 1c02e8f v1.2.0 && echo "está no release"

Os dois últimos comandos respondem a uma pergunta frequente do suporte: "a correção já chegou aos usuários ou não?" Se a correção entrou só na main e o release foi gerado antes, o git tag --contains mostra uma lista vazia, e fica claro que é preciso uma nova tag.

Outro truque é baixar o código-fonte de uma versão específica sem histórico: git archive --format=zip -o app-1.2.0.zip v1.2.0. Assim se geram pacotes para entrega ao cliente ou para build em ambiente isolado.

Como mudar para uma versão pela tag

git switch --detach v1.1.0
# HEAD is now at 1c02e8f fix: timeout das requisições

Você ficará em detached HEAD: dá para ver e compilar, mas os novos commits não pertencerão a nenhuma branch. Se precisar corrigir uma versão antiga, crie uma branch a partir da tag:

git switch -c hotfix/1.1.x v1.1.0
# alterações, commit
git tag -a v1.1.1 -m "Correção de segurança"
git push origin hotfix/1.1.x --follow-tags

Versionamento de releases: SemVer

O esquema de nomes de tags mais comum é o Semantic Versioning: MAJOR.MINOR.PATCH.

  • MAJOR sobe com mudanças incompatíveis na API: 1.4.2 → 2.0.0.
  • MINOR — nova funcionalidade mantendo a compatibilidade: 1.4.2 → 1.5.0.
  • PATCH — correções de bugs: 1.4.2 → 1.4.3.
  • Pré-releases levam um sufixo: 2.0.0-beta.1, 2.0.0-rc.1.

O prefixo v (v1.4.2) é uma convenção comum para nomes de tags; o SemVer em si não exige. O importante é escolher um formato e mantê-lo, senão os scripts que procuram o último release quebram.

Tags no processo de release

Um processo típico em equipe é assim:

  1. As alterações são integradas na main, testes verdes.
  2. Atualiza-se o CHANGELOG e o número da versão nos arquivos do projeto, se ele estiver lá.
  3. Cria-se uma tag anotada: git tag -a v1.5.0 -m "Release 1.5.0".
  4. git push origin main --follow-tags.
  5. O CI detecta a nova tag, gera os artefatos e publica o release; no GitHub e no GitLab, a partir da tag é criada uma página de Release com descrição e arquivos.

Assim, qualquer versão em produção pode ser associada sem ambiguidade ao código: a tag no nome do build — e com git show dá para ver o que entrou nele. Já git log v1.4.0..v1.5.0 --oneline dá a lista de alterações entre releases para as release notes.

Release notes a partir das tags

Se as mensagens de commit forem claras, as tags transformam o histórico em uma lista de alterações pronta. Dá para encontrar o último release e o anterior sem procurar à mão:

LAST=$(git describe --tags --abbrev=0)
PREV=$(git describe --tags --abbrev=0 "$LAST^")
git log "$PREV..$LAST" --no-merges --pretty=format:"- %s (%h)"
# - feat: exportação de relatórios (7be41d0)
# - fix: timeout das requisições (1c02e8f)

Se o time escreve commits seguindo os Conventional Commits (feat:, fix:, feat!:), o número da próxima versão pode ser calculado automaticamente: fix sobe o PATCH, feat o MINOR, ponto de exclamação ou BREAKING CHANGE o MAJOR. É nisso que se baseiam as ferramentas populares de release automático: elas mesmas criam a tag e escrevem o CHANGELOG.

Tags e CI/CD

Os pipelines costumam distinguir dois eventos: push em uma branch e criação de uma tag. Na branch rodam os testes e o build do ambiente de teste; na tag, a publicação. No GitHub Actions fica assim:

on:
  push:
    tags:
      - "v*.*.*"

No GitLab CI, o mesmo papel é feito pela variável CI_COMMIT_TAG e pela regra rules: - if: $CI_COMMIT_TAG. O nome da tag dentro do pipeline vira o número de versão da imagem Docker ou do pacote, por isso o formato das tags deve ser rígido e previsível.

Daí mais um motivo para não mover tags: se o pipeline já publicou o pacote 1.2.0 no registry, uma nova publicação com o mesmo número normalmente é proibida, e a imagem com a tag 1.2.0 continuará antiga para os usuários.

Nomes de tags: o que é permitido

O nome de uma tag segue as mesmas regras do nome de uma branch: sem espaços, sem os caracteres ~ ^ : ? * [ e sem dois pontos seguidos. A barra é permitida, por isso em monorepos aparecem tags como api/v1.2.0 e web/v3.0.1 — um conjunto de versões por pacote. Para validar o nome antes, use git check-ref-format "refs/tags/v1.2.0": em caso de erro, ele retorna um código diferente de zero.

Proteção de tags

Em repositórios de equipe, vale proteger as tags de release: GitHub e GitLab permitem bloquear a criação, a sobrescrita e a exclusão de tags por padrão (por exemplo, v*) para todos, exceto os mantenedores. Assim, um git push --tags acidental de outra máquina não publica um release não planejado, e um git push origin --delete por engano não apaga o histórico de versões.

Erros comuns

  • A tag não está no servidor. Esqueceu o git push origin <tag> ou o --follow-tags.
  • Tag com o mesmo nome de uma branch. O Git avisa refname is ambiguous; use o prefixo v para as tags e nomes diferentes.
  • Tag em um estado não commitado. A tag é colocada em um commit, não nos arquivos: alterações não commitadas não entram no release.
  • Tag leve para release. Sem autor, data e mensagem, e o git describe não a enxerga por padrão.

Resumo

O git tag fixa um ponto imutável no histórico: para releases, crie tags anotadas com git tag -a, nomeie-as seguindo o SemVer e envie-as ao servidor explicitamente — git push origin <tag> ou --follow-tags. Não mova tags publicadas; lance uma nova versão. Tags, junto com rebase, stash e cherry-pick, são praticadas no curso de Git.

Perguntas frequentes

Qual a diferença entre tag e branch?

A branch avança automaticamente a cada novo commit, enquanto a tag aponta para sempre para o mesmo commit.

Dá para colocar duas tags no mesmo commit?

Sim, não há limite de tags por commit, por exemplo v2.0.0 e latest-stable.

As tags são apagadas quando a branch é apagada?

Não, as tags são independentes das branches, e o commit com tag continua acessível mesmo depois de a branch ser apagada.

Como saber em qual release um commit entrou?

Rode git tag --contains &lt;hash&gt; — o comando mostra todas as tags cujo histórico inclui esse commit.

Como obter a última tag em um script?

Use git describe --tags --abbrev=0 — ele mostra o nome da tag mais próxima sem o sufixo com o hash.

Aprenda este tema em vídeo

Este tema é abordado em profundidade, com prática, no curso “Git do zero ao desenvolvedor confiante”.

Ir para o curso