|  | #!/bin/sh | 
|  | # Copyright (c) 2005 Linus Torvalds | 
|  |  | 
|  | USAGE='[-n [<num>]] -l [<pattern>] | [-a | -s | -u <key-id>] [-f | -d | -v] [-m <msg>] <tagname> [<head>]' | 
|  | SUBDIRECTORY_OK='Yes' | 
|  | . git-sh-setup | 
|  |  | 
|  | message_given= | 
|  | annotate= | 
|  | signed= | 
|  | force= | 
|  | message= | 
|  | username= | 
|  | list= | 
|  | verify= | 
|  | LINES=0 | 
|  | while test $# != 0 | 
|  | do | 
|  | case "$1" in | 
|  | -a) | 
|  | annotate=1 | 
|  | shift | 
|  | ;; | 
|  | -s) | 
|  | annotate=1 | 
|  | signed=1 | 
|  | shift | 
|  | ;; | 
|  | -f) | 
|  | force=1 | 
|  | shift | 
|  | ;; | 
|  | -n) | 
|  | case "$#,$2" in | 
|  | 1,* | *,-*) | 
|  | LINES=1 	# no argument | 
|  | ;; | 
|  | *)	shift | 
|  | LINES=$(expr "$1" : '\([0-9]*\)') | 
|  | [ -z "$LINES" ] && LINES=1 # 1 line is default when -n is used | 
|  | ;; | 
|  | esac | 
|  | shift | 
|  | ;; | 
|  | -l) | 
|  | list=1 | 
|  | shift | 
|  | case $# in | 
|  | 0)	PATTERN= | 
|  | ;; | 
|  | *) | 
|  | PATTERN="$1"	# select tags by shell pattern, not re | 
|  | shift | 
|  | ;; | 
|  | esac | 
|  | git rev-parse --symbolic --tags | sort | | 
|  | while read TAG | 
|  | do | 
|  | case "$TAG" in | 
|  | *$PATTERN*) ;; | 
|  | *)	    continue ;; | 
|  | esac | 
|  | [ "$LINES" -le 0 ] && { echo "$TAG"; continue ;} | 
|  | OBJTYPE=$(git cat-file -t "$TAG") | 
|  | case $OBJTYPE in | 
|  | tag) | 
|  | ANNOTATION=$(git cat-file tag "$TAG" | | 
|  | sed -e '1,/^$/d' | | 
|  | sed -n -e " | 
|  | /^-----BEGIN PGP SIGNATURE-----\$/q | 
|  | 2,\$s/^/    / | 
|  | p | 
|  | ${LINES}q | 
|  | ") | 
|  | printf "%-15s %s\n" "$TAG" "$ANNOTATION" | 
|  | ;; | 
|  | *)      echo "$TAG" | 
|  | ;; | 
|  | esac | 
|  | done | 
|  | ;; | 
|  | -m) | 
|  | annotate=1 | 
|  | shift | 
|  | message="$1" | 
|  | if test "$#" = "0"; then | 
|  | die "error: option -m needs an argument" | 
|  | else | 
|  | message="$1" | 
|  | message_given=1 | 
|  | shift | 
|  | fi | 
|  | ;; | 
|  | -F) | 
|  | annotate=1 | 
|  | shift | 
|  | if test "$#" = "0"; then | 
|  | die "error: option -F needs an argument" | 
|  | else | 
|  | message="$(cat "$1")" | 
|  | message_given=1 | 
|  | shift | 
|  | fi | 
|  | ;; | 
|  | -u) | 
|  | annotate=1 | 
|  | signed=1 | 
|  | shift | 
|  | if test "$#" = "0"; then | 
|  | die "error: option -u needs an argument" | 
|  | else | 
|  | username="$1" | 
|  | shift | 
|  | fi | 
|  | ;; | 
|  | -d) | 
|  | shift | 
|  | had_error=0 | 
|  | for tag | 
|  | do | 
|  | cur=$(git show-ref --verify --hash -- "refs/tags/$tag") || { | 
|  | echo >&2 "Seriously, what tag are you talking about?" | 
|  | had_error=1 | 
|  | continue | 
|  | } | 
|  | git update-ref -m 'tag: delete' -d "refs/tags/$tag" "$cur" || { | 
|  | had_error=1 | 
|  | continue | 
|  | } | 
|  | echo "Deleted tag $tag." | 
|  | done | 
|  | exit $had_error | 
|  | ;; | 
|  | -v) | 
|  | shift | 
|  | tag_name="$1" | 
|  | tag=$(git show-ref --verify --hash -- "refs/tags/$tag_name") || | 
|  | die "Seriously, what tag are you talking about?" | 
|  | git-verify-tag -v "$tag" | 
|  | exit $? | 
|  | ;; | 
|  | -*) | 
|  | usage | 
|  | ;; | 
|  | *) | 
|  | break | 
|  | ;; | 
|  | esac | 
|  | done | 
|  |  | 
|  | [ -n "$list" ] && exit 0 | 
|  |  | 
|  | name="$1" | 
|  | [ "$name" ] || usage | 
|  | prev=0000000000000000000000000000000000000000 | 
|  | if git show-ref --verify --quiet -- "refs/tags/$name" | 
|  | then | 
|  | test -n "$force" || die "tag '$name' already exists" | 
|  | prev=`git rev-parse "refs/tags/$name"` | 
|  | fi | 
|  | shift | 
|  | git check-ref-format "tags/$name" || | 
|  | die "we do not like '$name' as a tag name." | 
|  |  | 
|  | object=$(git rev-parse --verify --default HEAD "$@") || exit 1 | 
|  | type=$(git cat-file -t $object) || exit 1 | 
|  | tagger=$(git var GIT_COMMITTER_IDENT) || exit 1 | 
|  |  | 
|  | test -n "$username" || | 
|  | username=$(git config user.signingkey) || | 
|  | username=$(expr "z$tagger" : 'z\(.*>\)') | 
|  |  | 
|  | trap 'rm -f "$GIT_DIR"/TAG_TMP* "$GIT_DIR"/TAG_FINALMSG "$GIT_DIR"/TAG_EDITMSG' 0 | 
|  |  | 
|  | if [ "$annotate" ]; then | 
|  | if [ -z "$message_given" ]; then | 
|  | ( echo "#" | 
|  | echo "# Write a tag message" | 
|  | echo "#" ) > "$GIT_DIR"/TAG_EDITMSG | 
|  | git_editor "$GIT_DIR"/TAG_EDITMSG || exit | 
|  | else | 
|  | printf '%s\n' "$message" >"$GIT_DIR"/TAG_EDITMSG | 
|  | fi | 
|  |  | 
|  | grep -v '^#' <"$GIT_DIR"/TAG_EDITMSG | | 
|  | git stripspace >"$GIT_DIR"/TAG_FINALMSG | 
|  |  | 
|  | [ -s "$GIT_DIR"/TAG_FINALMSG -o -n "$message_given" ] || { | 
|  | echo >&2 "No tag message?" | 
|  | exit 1 | 
|  | } | 
|  |  | 
|  | ( printf 'object %s\ntype %s\ntag %s\ntagger %s\n\n' \ | 
|  | "$object" "$type" "$name" "$tagger"; | 
|  | cat "$GIT_DIR"/TAG_FINALMSG ) >"$GIT_DIR"/TAG_TMP | 
|  | rm -f "$GIT_DIR"/TAG_TMP.asc "$GIT_DIR"/TAG_FINALMSG | 
|  | if [ "$signed" ]; then | 
|  | gpg -bsa -u "$username" "$GIT_DIR"/TAG_TMP && | 
|  | cat "$GIT_DIR"/TAG_TMP.asc >>"$GIT_DIR"/TAG_TMP || | 
|  | die "failed to sign the tag with GPG." | 
|  | fi | 
|  | object=$(git-mktag < "$GIT_DIR"/TAG_TMP) | 
|  | fi | 
|  |  | 
|  | git update-ref "refs/tags/$name" "$object" "$prev" |