2009-10-20 6 views
34

Dans un environnement de script Unix ou GNU (par exemple, une distribution Linux, Cygwin, OSX), quelle est la meilleure façon de déterminer si la caisse actuelle est un tag Git. Si c'est une étiquette, comment puis-je déterminer le nom de l'étiquette?Comment déterminer par programmation si la vérification Git est une étiquette et si oui, quel est le nom du tag

Une utilisation de cette technique serait l'étiquetage automatique d'une version (comme svnversion ferait avec Subversion).

Voir mes questions connexes à propos de programmatically detecting the Git branch.

+0

Jetez un oeil à scénario GIT-VERSION-GEN (et son utilisation dans Makefile) dans le dépôt git: http://git.kernel.org/?p=git/git.git;a=blob;f=GIT-VERSION-GEN;hb=HEAD –

+0

@jhs: j'ai mis en doute Greg Hewgill réponse . J'ai répondu downvoted basé sur 'git name-rev' parce qu'il peut retourner par exemple. 'some-tag ~ 5', et réponds en fonction de la combinaison de 'git log' et' git tag -l' car il est moche et inefficace. –

Répondre

36

La solution à votre question est d'utiliser

git describe --exact-match HEAD 

(qui ne tiendrait compte que annotés balises, mais vous devez utiliser annotée et probablement même signé des étiquettes pour le marquage de presse).

Si vous voulez examiner tous les tags, aussi légers tags (qui sont généralement utilisés pour le marquage local), vous pouvez utiliser l'option --tags:

git describe --exact-match --tags HEAD 

Mais je pense que vous avez " XY problem "ici, en ce que vous posez des questions sur la solution possible au problème, plutôt que de poser une question sur un problème ... qui peut avoir une meilleure solution.

La solution à votre problème est de jeter un oeil comment Git il le fait dans GIT-VERSION-GEN script et la façon dont il utilise dans son Makefile.

+2

Jakub, avec tout le respect que je vous dois, vos recommandations concernant mon processus de libération, et vos spéculations sur mon vrai problème, sont toutes deux hors de propos. Merci pour votre solution technique, cependant. – JasonSmith

+0

Malheureusement, votre solution ne fonctionne pas pour moi. 'git describe --exact-match HEAD' =>' fatal: aucune balise ne correspond exactement à '...'. Je crois que vous devez ajouter '--tags' aux paramètres. – JasonSmith

+0

@jhs: Wbout 'git décrire --exact-match HEAD' vs' git describe --exact-match --tags HEAD': L'option '--tags' ne serait nécessaire que si vous utilisez des balises légères. Il est recommandé d'utiliser des balises signées (qui sont des balises annotées, c'est-à-dire des objets d'étiquettes) pour étiqueter les versions. –

-2

Voici un bref script shell (testé dans Bash, non confirmé s'il fonctionne sur cendres, etc.). Il va définir la variable git_tag sur le nom de la balise actuellement retirée, ou la laisser vide si le checkout n'est pas étiqueté.

git_tag='' 
this_commit=`git log --pretty=format:%H%n HEAD^..` 

for tag in `git tag -l`; do 
    tag_commit=`git log --pretty=format:%H%n tags/$tag^..tags/$tag` 
    if [ "$this_commit" = "$tag_commit" ]; then 
    # This is a tagged commit, so use the tag. 
    git_tag="$tag" 
    fi 
done 

Commentaire de Jakub Narębski:

Cette solution réduit à effectuer une boucle sur toutes les étiquettes, et vérifier si elles pointent à Corrent engager, à savoir l'objet pointé par HEAD. En utilisant les commandes de plomberie, à savoir les commandes destinées pour les scripts, cela peut être écrit:

this_commit=$(git rev-parse --verify HEAD) 
git for-each-ref --format="%(*objectname) %(refname:short)" refs/tags/ | 
while read tagged_object tagname 
do 
    if test "$this_commit" = "$tagged_object" 
    then 
     echo $tagname 
    fi 
done 

Ce imprimerait toutes les balises qui pointent à engager en cours.

+0

Utilisez "git rev-parse HEAD" pour obtenir SHA-1 de la validation en cours, pas besoin de solution compliquée avec git-log. Utilisez git-for-each-ref au lieu d'une solution compliquée avec "git tag -l" et "git log" (et pas même "git show"). Utilisez "git describe" pour répondre à une question originale. Utilisez GIT-VERSION-GEN pour résoudre le problème. –

2

Une meilleure solution (de la réponse de Greg Hewgill dans l'autre question) serait:

git name-rev --name-only --tags HEAD 

Si elle retourne « non défini », alors vous n'êtes pas sur une étiquette. Sinon, il renvoie le nom du tag. Ainsi, un one-liner pour faire quelque chose comme mon autre réponse serait:

git_tag=`git name-rev --name-only --tags HEAD | sed 's/^undefined$//'` 

exemple de shell interactif de la façon dont cela fonctionne:

$ git checkout master 
Already on "master" 
$ git name-rev --name-only --tags HEAD 
undefined 
$ git checkout some-tag 
Note: moving to "some-tag" which isnt a local branch 
If you want to create a new branch from this checkout, you may do so 
(now or later) by using -b with the checkout command again. Example: 
    git checkout -b <new_branch_name> 
HEAD is now at 1234567... Some comment blah blah 
$ git name-rev --name-only --tags HEAD 
some-tag 
+2

Cela ne fonctionnerait pas correctement si HEAD est ** joignable ** à partir de la balise (par exemple via une autre branche qui est en avance sur la branche actuellement extraite), mais pas sur une balise elle-même. Vous obtiendrez des résultats comme: "some-tag ~ 3" –

+0

Aussi, pour être nitpicky, il pourrait y avoir une étiquette nommée 'undefined' ... –

5

La meilleure façon de le faire est d'utiliser la commande git describe:

git-décrire - Afficher la balise la plus récente qui est accessible à partir d'un engagement

la commande trouve la balise la plus récente accessible depuis un commit. Si la balise pointe vers le commit, seule la balise est affichée. Sinon, il suffixe le nom de la balise avec le nombre de validations supplémentaires au-dessus de l'objet balisé et le nom abrégé de l'objet de la validation la plus récente.

+0

Merci. git-describe ne semble pas aussi facile à utiliser dans un script shell pour cet objectif spécifique comparé à git-name-rev. – JasonSmith

+0

Je dis cela parce que, d'abord git-décrire les erreurs lors de l'exécution sur une branche sans arguments. Recommanderiez-vous 'git-describe --tags'? Mais plus important encore, il n'est pas trivial de dire si vous êtes sur une bonne étiquette ou non. Vous devez analyser la sortie et rechercher des traits d'union. Mais que faire si le nom du tag contient des hypens? Pour cette raison je préfère 'git name-ref --name-only --tags HEAD' – JasonSmith

+0

Assez juste, je suppose que la meilleure option dépend de votre application particulière. J'ai utilisé 'git describe' dans le passé pour étiqueter automatiquement une version. –

4

Utilisation de git-nom-rev est préféré pour les scripts, car il fait partie de la plomberie git , alors que git-décrivent fait partie de porcelaine.

Utilisez cette commande pour imprimer le nom de l'étiquette si le HEAD pointe sur un, sinon rien.

git name-rev --name-only --tags --no-undefined HEAD 2>/dev/null | sed -n 's/^\([^^~]\{1,\}\)\(\^0\)\{0,1\}$/\1/p' 

Remarque la redirection des flux vers/dev/null - sinon vous aurez un message d'erreur indiquant:

fatal: cannot describe 'SOMESHA'" 

EDIT: Correction du regex dans sed pour soutenir à la fois lighweight et annoté/tags signés.

2

Vous ne pouvez pas déterminer si l'extraction en cours "est une étiquette". Vous pouvez uniquement déterminer si la vérification en cours était un commit ayant des tags. La différence est la suivante: s'il y a plusieurs balises pointant vers cette validation, git ne peut pas vous dire lequel vous avez utilisé pour vérifier, ni si vous en avez réellement utilisé un pour y arriver du tout.

Jakub’s answer here basé sur git describe --exact-match (--tags) vous donne « le premier » de toutes les balises (annotés).

Et git describe les trie comme ceci:

  • balises annotées premiers
    • les plus jeunes d'abord triés
  • balises légères viennent ensuite
    • binaire triées par nom de la balise (qui signifie par ordre alphabétique si elle est codée en anglais ASCII)
    • git ne stocke pas les méta-données avec des balises légères, donc « plus jeune premier » ne peut pas être réalisé
Questions connexes