Tutoriel

Les tags dans Git : utiliser git tag et versionner vos releases

Mis à jour: · Skillaria.Top

git tag pose une étiquette permanente sur un commit précis, généralement pour marquer une release, par exemple v1.2.0. Un tag annoté se crée avec git tag -a v1.2.0 -m "message", et les tags s'envoient séparément sur le serveur : git push origin v1.2.0 ou git push --tags.

git tag est une étiquette nommée posée sur un commit précis. Contrairement à une branche, un tag ne bouge pas quand de nouveaux commits arrivent : v1.2.0 désignera encore dans un an le même instantané du code. C'est pourquoi on utilise les tags pour les releases, et les systèmes de CI/CD lancent souvent le build et la publication justement à l'apparition d'un tag.

Tags légers et tags annotés

Git propose deux types de tags, et la différence compte.

Léger (lightweight)Annoté (annotated)
Créationgit tag v1.0.0git tag -a v1.0.0 -m "..."
Natureun simple pointeur vers un commitun objet à part entière dans la base Git
Auteur, date, messagenonoui
Signature GPG/SSHnonpossible (-s)
Pris en compte par git describe par défautnonoui
Quand l'utiliserrepères personnels temporairesreleases et tout ce qui est publié

Pour les releases, utilisez des tags annotés : ils enregistrent qui a publié la version et quand, et ils peuvent être signés.

Comment créer un tag

Sur le commit courant

git tag -a v1.2.0 -m "Release 1.2.0 : export des rapports, timeout de l'API corrigé"

Sans -m, Git ouvre l'éditeur pour le message — pratique si vous voulez y rédiger la liste des changements.

Sur un ancien commit

Vous avez oublié de taguer lors de la release ? Pas de souci, on peut poser un tag sur n'importe quel commit :

git log --oneline -5
# 7be41d0 feat: export des rapports
# 1c02e8f fix: timeout des requêtes
git tag -a v1.1.0 1c02e8f -m "Release 1.1.0"

Tag signé

git tag -s v1.2.0 -m "Release 1.2.0"
git tag -v v1.2.0     # vérifier la signature

Il faut une clé GPG configurée (ou SSH avec gpg.format=ssh). GitHub et GitLab affichent ces tags avec une mention « vérifié ».

Comment lister les tags

git tag                       # tous les tags par ordre alphabétique
git tag -l "v1.*"             # selon un motif
git tag -n                    # avec la première ligne du message
git tag --sort=-v:refname     # par version, les plus récents en haut
git show v1.2.0               # infos du tag et commit
git describe --tags           # tag le plus proche : v1.2.0-3-g7be41d0

Attention au tri : par défaut, v1.10.0 apparaît avant v1.9.0, car les chaînes sont comparées caractère par caractère. L'option --sort=v:refname trie comme des numéros de version.

La sortie de git describe se lit ainsi : trois commits après le tag v1.2.0, commit courant 7be41d0 (la lettre g signifie git). C'est une source pratique de numéro de version pour les builds entre deux releases.

Comment pousser un tag sur le serveur

Un git push ordinaire n'envoie pas les tags — c'est la cause fréquente de la question « pourquoi mon tag n'est pas sur GitHub ».

git push origin v1.2.0        # un seul tag
git push --tags               # tous les tags locaux
git push --follow-tags        # les commits + les tags annotés qui pointent dessus

--follow-tags est plus sûr que --tags : il n'envoie pas les tags légers que vous aviez posés pour vous-même. Vous pouvez l'activer par défaut : git config --global push.followTags true.

Pour récupérer les tags du serveur : git fetch --tags. Un git fetch ordinaire récupère aussi les tags qui pointent vers les commits téléchargés.

Comment supprimer ou déplacer un tag

Suppression

git tag -d v1.2.0                     # en local
git push origin --delete v1.2.0       # sur le serveur
# ancienne syntaxe équivalente : git push origin :refs/tags/v1.2.0

Déplacer un tag vers un autre commit

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

Techniquement, c'est possible, mais dans un projet public mieux vaut ne pas déplacer un tag déjà publié. Chez ceux qui l'ont déjà récupéré, il ne se mettra pas à jour tout seul : Git n'écrase pas les tags locaux existants lors d'un fetch sans --force. Au final, « v1.2.0 » désignera un code différent selon les personnes. Mieux vaut publier v1.2.1.

Comment savoir quels commits sont entrés dans une release

Les tags servent de bornes de plages dans toutes les commandes de lecture de l'historique :

git log v1.1.0..v1.2.0 --oneline        # commits entre deux releases
git diff v1.1.0 v1.2.0 --stat           # fichiers modifiés
git tag --contains 1c02e8f              # releases qui contiennent ce commit
git merge-base --is-ancestor 1c02e8f v1.2.0 && echo "présent dans la release"

Les deux dernières commandes répondent à une question fréquente du support : « le correctif est-il déjà arrivé chez les utilisateurs ? » Si le correctif n'est que dans main et que la release a été construite avant, git tag --contains renverra une liste vide, et vous saurez qu'il faut un nouveau tag.

Autre astuce : télécharger les sources d'une version précise sans l'historique : git archive --format=zip -o app-1.2.0.zip v1.2.0. C'est ainsi qu'on prépare des archives à livrer à un client ou à construire dans un environnement isolé.

Comment se placer sur une version à partir d'un tag

git switch --detach v1.1.0
# HEAD is now at 1c02e8f fix: timeout des requêtes

Vous êtes alors en detached HEAD : vous pouvez consulter et construire, mais les nouveaux commits n'appartiendront à aucune branche. Pour corriger une ancienne version, créez une branche à partir du tag :

git switch -c hotfix/1.1.x v1.1.0
# modifications, commit
git tag -a v1.1.1 -m "Correctif de sécurité"
git push origin hotfix/1.1.x --follow-tags

Versionner les releases : SemVer

Le schéma de nommage de tags le plus répandu est le Semantic Versioning : MAJOR.MINOR.PATCH.

  • MAJOR augmente en cas de changements incompatibles de l'API : 1.4.2 → 2.0.0.
  • MINOR — nouvelles fonctionnalités rétrocompatibles : 1.4.2 → 1.5.0.
  • PATCH — corrections de bugs : 1.4.2 → 1.4.3.
  • Les préversions sont marquées par un suffixe : 2.0.0-beta.1, 2.0.0-rc.1.

Le préfixe v (v1.4.2) est une convention courante pour les noms de tags, SemVer ne l'impose pas. L'essentiel est de choisir un format et de s'y tenir, sinon les scripts qui cherchent la dernière release ne fonctionneront plus.

Les tags dans le processus de release

En équipe, le processus type ressemble à ceci :

  1. Les changements sont fusionnés dans main, les tests sont au vert.
  2. On met à jour le CHANGELOG et le numéro de version dans les fichiers du projet, s'il y figure.
  3. On pose un tag annoté : git tag -a v1.5.0 -m "Release 1.5.0".
  4. git push origin main --follow-tags.
  5. La CI détecte le nouveau tag, construit les artefacts et publie la release ; sur GitHub et GitLab, une page Release avec description et fichiers est créée à partir du tag.

Ainsi, chaque version en production peut être reliée sans ambiguïté au code : le tag figure dans le nom du build, et git show montre ce qu'il contient. Et git log v1.4.0..v1.5.0 --oneline fournit la liste des changements entre deux releases pour les notes de version.

Notes de version à partir des tags

Si les messages de commit sont parlants, les tags transforment l'historique en liste de changements toute prête. La dernière et l'avant-dernière release se retrouvent sans recherche manuelle :

LAST=$(git describe --tags --abbrev=0)
PREV=$(git describe --tags --abbrev=0 "$LAST^")
git log "$PREV..$LAST" --no-merges --pretty=format:"- %s (%h)"
# - feat: export des rapports (7be41d0)
# - fix: timeout des requêtes (1c02e8f)

Si l'équipe suit la convention Conventional Commits (feat:, fix:, feat!:), le numéro de la prochaine version peut être calculé automatiquement : fix incrémente PATCH, feat MINOR, un point d'exclamation ou BREAKING CHANGE MAJOR. Les outils populaires de release automatique reposent sur ce principe : ils posent eux-mêmes le tag et rédigent le CHANGELOG.

Tags et CI/CD

Les pipelines distinguent généralement deux événements : un push sur une branche et l'apparition d'un tag. Sur une branche, on lance les tests et le déploiement d'un environnement de test ; sur un tag, la publication. Dans GitHub Actions, cela donne :

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

Dans GitLab CI, ce rôle est joué par la variable CI_COMMIT_TAG et la règle rules: - if: $CI_COMMIT_TAG. Dans le pipeline, le nom du tag devient le numéro de version de l'image Docker ou du paquet ; le format des tags doit donc être strict et prévisible.

D'où une raison de plus de ne pas déplacer les tags : si le pipeline a déjà publié le paquet 1.2.0 dans un registre, une nouvelle publication sous le même numéro est en général interdite, et l'image taguée 1.2.0 restera l'ancienne chez les utilisateurs.

Nommer les tags : ce qui est autorisé

Le nom d'un tag obéit aux mêmes règles que celui d'une branche : pas d'espaces, pas de caractères ~ ^ : ? * [ ni de deux points consécutifs. La barre oblique est permise, c'est pourquoi on trouve dans les monorepos des tags comme api/v1.2.0 et web/v3.0.1 — une série de versions par paquet. Vous pouvez valider un nom à l'avance avec git check-ref-format "refs/tags/v1.2.0" : en cas d'erreur, la commande renvoie un code non nul.

Protéger les tags

Dans les dépôts d'équipe, il vaut mieux protéger les tags de release : GitHub et GitLab permettent d'interdire la création, la réécriture et la suppression des tags correspondant à un motif (par exemple v*) à tous sauf aux mainteneurs. Ainsi, un git push --tags lancé par erreur depuis une autre machine ne publiera pas de release imprévue, et un git push origin --delete malheureux n'effacera pas l'historique des versions.

Erreurs fréquentes

  • Le tag n'est pas sur le serveur. Vous avez oublié git push origin <tag> ou --follow-tags.
  • Un tag porte le même nom qu'une branche. Git affiche l'avertissement refname is ambiguous ; utilisez le préfixe v pour les tags et des noms distincts.
  • Tag sur un état non commité. Un tag se pose sur un commit, pas sur des fichiers : les modifications non commitées n'entreront pas dans la release.
  • Tag léger pour une release. Pas d'auteur, de date ni de message, et git describe ne le voit pas par défaut.

En résumé

git tag fixe un point immuable dans l'historique : pour les releases, créez des tags annotés avec git tag -a, nommez-les selon SemVer et envoyez-les explicitement sur le serveur — git push origin <tag> ou --follow-tags. Ne déplacez pas un tag publié, publiez plutôt une nouvelle version. Les tags, comme rebase, stash et cherry-pick, sont mis en pratique dans le cours Git.

Questions fréquentes

Quelle est la différence entre un tag et une branche ?

Une branche avance automatiquement à chaque nouveau commit, alors qu'un tag désigne pour toujours le même commit.

Peut-on mettre deux tags sur le même commit ?

Oui, le nombre de tags par commit n'est pas limité, par exemple v2.0.0 et latest-stable.

Les tags sont-ils supprimés quand on supprime une branche ?

Non, les tags sont indépendants des branches, et un commit tagué reste accessible même après la suppression de la branche.

Comment savoir dans quelle release se trouve un commit ?

Lancez git tag --contains &lt;hash&gt; — la commande affiche tous les tags dont l'historique contient ce commit.

Comment obtenir le dernier tag dans un script ?

Utilisez git describe --tags --abbrev=0 — il affiche le nom du tag le plus proche sans le suffixe de hash.

Apprenez ce sujet en vidéo

Ce sujet est traité en détail avec de la pratique dans le cours « Git de zéro à développeur confirmé ».

Voir le cours