Как программно определить, является ли проверка Git тегом, и если да, то каково имя тега
В среде сценариев Unix или GNU (например, дистрибутив Linux, Cygwin, OSX), как лучше всего определить, является ли текущая проверка Git-тегом. Если это тег, как я могу определить имя тега?
Одним из применений этой техники будет автоматическая маркировка релиза (например, svnversion
будет делать с Subversion).
Смотрите мой связанный вопрос о программном обнаружении ветви Git.
6 ответов
Решение вашего вопроса заключается в использовании
git describe --exact-match HEAD
(который будет учитывать только аннотированные теги, но вы должны использовать аннотированные и, возможно, даже подписанные теги для маркировки релизов).
Если вы хотите рассмотреть все теги, а также легкие теги (которые обычно используются для локальных тегов), вы можете использовать --tags
опция:
git describe --exact-match --tags HEAD
Но я думаю, что у вас есть " проблема XY", когда вы задаете вопрос о возможном решении проблемы, а не задаете вопрос о проблеме... которая может иметь лучшее решение.
Решение вашей проблемы - посмотреть, как Git делает это в скрипте GIT-VERSION-GEN, и как он использует его в своем Makefile.
Лучшее решение (из ответа Грега Хьюгилла в другом вопросе) было бы:
git name-rev --name-only --tags HEAD
Если он возвращает "undefined", значит, вы не в теге. В противном случае он возвращает имя тега. Таким образом, однострочник, чтобы сделать что-то вроде моего другого ответа будет:
git_tag=`git name-rev --name-only --tags HEAD | sed 's/^undefined$//'`
Пример интерактивной оболочки о том, как это работает:
$ 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
Использование git-name-rev является предпочтительным для сценариев, так как оно является частью git- сантехники, тогда как git-description является частью фарфора.
Используйте эту команду, чтобы напечатать имя тега, если заголовок указывает на один, иначе ничего.
git name-rev --name-only --tags --no-undefined HEAD 2>/dev/null | sed -n 's/^\([^^~]\{1,\}\)\(\^0\)\{0,1\}$/\1/p'
Обратите внимание на перенаправление stderr на /dev/null - в противном случае вы получите сообщение об ошибке:
fatal: cannot describe 'SOMESHA'"
РЕДАКТИРОВАТЬ: Исправлено регулярное выражение в sed для поддержки как облегченных, так и аннотированных / подписанных тегов.
Лучший способ сделать это - использовать git describe
команда:
git-description - Показать самый последний тег, который доступен из коммита
Команда находит самый последний тег, доступный из коммита. Если тег указывает на фиксацию, отображается только тег. В противном случае он добавляет суффикс имени тега к числу дополнительных коммитов поверх помеченного объекта и сокращенному имени объекта самого последнего коммита.
Вы не можете определить, является ли текущая проверка "тегом". Вы можете только определить, была ли текущая проверка фиксацией, имеющей теги.
Разница в том, что если есть несколько тегов, указывающих на этот коммит, git не может сказать вам, что вы использовали для извлечения, и если вы вообще использовали один, чтобы попасть туда вообще.
Ответ Якуба здесь основан на git describe --exact-match (--tags)
дает вам "первый" из всех (аннотированных) тегов.
А также git describe
сортирует их так:
- сначала помеченные теги
- отсортировано младшим первым
- легкие метки приходят потом
- двоичный файл, отсортированный по имени тега (это означает, что в алфавитном порядке, если это английский кодируется в ASCII)
- git не хранит метаданные с легкими тегами, поэтому "младший первый" не может быть реализован
Вот краткий скрипт оболочки (протестирован в Bash, не подтвержден, работает ли он на золе и т. Д.). Это установит git_tag
переменная к имени текущего извлеченного тега, или оставьте это поле пустым, если извлечение не помечено.
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
Комментарий Якуба Наренбского:
Это решение сводится к тому, чтобы зацикливаться на всех тегах и проверять, указывают ли они на корректную фиксацию, то есть объект, на который указывает HEAD. Используя сантехнические команды, то есть команды, предназначенные для сценариев, это можно записать так:
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
Это напечатало бы все теги, которые указывают на текущий коммит.