Merge branch 'jc/fsck-nul-in-commit' into maint
[git] / contrib / examples / git-tag.sh
1 #!/bin/sh
2 # Copyright (c) 2005 Linus Torvalds
3
4 USAGE='[-n [<num>]] -l [<pattern>] | [-a | -s | -u <key-id>] [-f | -d | -v] [-m <msg>] <tagname> [<head>]'
5 SUBDIRECTORY_OK='Yes'
6 . git-sh-setup
7
8 message_given=
9 annotate=
10 signed=
11 force=
12 message=
13 username=
14 list=
15 verify=
16 LINES=0
17 while test $# != 0
18 do
19     case "$1" in
20     -a)
21         annotate=1
22         shift
23         ;;
24     -s)
25         annotate=1
26         signed=1
27         shift
28         ;;
29     -f)
30         force=1
31         shift
32         ;;
33     -n)
34         case "$#,$2" in
35         1,* | *,-*)
36                 LINES=1         # no argument
37                 ;;
38         *)      shift
39                 LINES=$(expr "$1" : '\([0-9]*\)')
40                 [ -z "$LINES" ] && LINES=1 # 1 line is default when -n is used
41                 ;;
42         esac
43         shift
44         ;;
45     -l)
46         list=1
47         shift
48         case $# in
49         0)      PATTERN=
50                 ;;
51         *)
52                 PATTERN="$1"    # select tags by shell pattern, not re
53                 shift
54                 ;;
55         esac
56         git rev-parse --symbolic --tags | sort |
57             while read TAG
58             do
59                 case "$TAG" in
60                 *$PATTERN*) ;;
61                 *)          continue ;;
62                 esac
63                 [ "$LINES" -le 0 ] && { echo "$TAG"; continue ;}
64                 OBJTYPE=$(git cat-file -t "$TAG")
65                 case $OBJTYPE in
66                 tag)
67                         ANNOTATION=$(git cat-file tag "$TAG" |
68                                 sed -e '1,/^$/d' |
69                                 sed -n -e "
70                                         /^-----BEGIN PGP SIGNATURE-----\$/q
71                                         2,\$s/^/    /
72                                         p
73                                         ${LINES}q
74                                 ")
75                         printf "%-15s %s\n" "$TAG" "$ANNOTATION"
76                         ;;
77                 *)      echo "$TAG"
78                         ;;
79                 esac
80             done
81         ;;
82     -m)
83         annotate=1
84         shift
85         message="$1"
86         if test "$#" = "0"; then
87             die "error: option -m needs an argument"
88         else
89             message="$1"
90             message_given=1
91             shift
92         fi
93         ;;
94     -F)
95         annotate=1
96         shift
97         if test "$#" = "0"; then
98             die "error: option -F needs an argument"
99         else
100             message="$(cat "$1")"
101             message_given=1
102             shift
103         fi
104         ;;
105     -u)
106         annotate=1
107         signed=1
108         shift
109         if test "$#" = "0"; then
110             die "error: option -u needs an argument"
111         else
112             username="$1"
113             shift
114         fi
115         ;;
116     -d)
117         shift
118         had_error=0
119         for tag
120         do
121                 cur=$(git show-ref --verify --hash -- "refs/tags/$tag") || {
122                         echo >&2 "Seriously, what tag are you talking about?"
123                         had_error=1
124                         continue
125                 }
126                 git update-ref -m 'tag: delete' -d "refs/tags/$tag" "$cur" || {
127                         had_error=1
128                         continue
129                 }
130                 echo "Deleted tag $tag."
131         done
132         exit $had_error
133         ;;
134     -v)
135         shift
136         tag_name="$1"
137         tag=$(git show-ref --verify --hash -- "refs/tags/$tag_name") ||
138                 die "Seriously, what tag are you talking about?"
139         git-verify-tag -v "$tag"
140         exit $?
141         ;;
142     -*)
143         usage
144         ;;
145     *)
146         break
147         ;;
148     esac
149 done
150
151 [ -n "$list" ] && exit 0
152
153 name="$1"
154 [ "$name" ] || usage
155 prev=0000000000000000000000000000000000000000
156 if git show-ref --verify --quiet -- "refs/tags/$name"
157 then
158     test -n "$force" || die "tag '$name' already exists"
159     prev=$(git rev-parse "refs/tags/$name")
160 fi
161 shift
162 git check-ref-format "tags/$name" ||
163         die "we do not like '$name' as a tag name."
164
165 object=$(git rev-parse --verify --default HEAD "$@") || exit 1
166 type=$(git cat-file -t $object) || exit 1
167 tagger=$(git var GIT_COMMITTER_IDENT) || exit 1
168
169 test -n "$username" ||
170         username=$(git config user.signingkey) ||
171         username=$(expr "z$tagger" : 'z\(.*>\)')
172
173 trap 'rm -f "$GIT_DIR"/TAG_TMP* "$GIT_DIR"/TAG_FINALMSG "$GIT_DIR"/TAG_EDITMSG' 0
174
175 if [ "$annotate" ]; then
176     if [ -z "$message_given" ]; then
177         ( echo "#"
178           echo "# Write a tag message"
179           echo "#" ) > "$GIT_DIR"/TAG_EDITMSG
180         git_editor "$GIT_DIR"/TAG_EDITMSG || exit
181     else
182         printf '%s\n' "$message" >"$GIT_DIR"/TAG_EDITMSG
183     fi
184
185     grep -v '^#' <"$GIT_DIR"/TAG_EDITMSG |
186     git stripspace >"$GIT_DIR"/TAG_FINALMSG
187
188     [ -s "$GIT_DIR"/TAG_FINALMSG -o -n "$message_given" ] || {
189         echo >&2 "No tag message?"
190         exit 1
191     }
192
193     ( printf 'object %s\ntype %s\ntag %s\ntagger %s\n\n' \
194         "$object" "$type" "$name" "$tagger";
195       cat "$GIT_DIR"/TAG_FINALMSG ) >"$GIT_DIR"/TAG_TMP
196     rm -f "$GIT_DIR"/TAG_TMP.asc "$GIT_DIR"/TAG_FINALMSG
197     if [ "$signed" ]; then
198         gpg -bsa -u "$username" "$GIT_DIR"/TAG_TMP &&
199         cat "$GIT_DIR"/TAG_TMP.asc >>"$GIT_DIR"/TAG_TMP ||
200         die "failed to sign the tag with GPG."
201     fi
202     object=$(git-mktag < "$GIT_DIR"/TAG_TMP)
203 fi
204
205 git update-ref "refs/tags/$name" "$object" "$prev"