]> git.ipfire.org Git - thirdparty/git.git/blame - templates/hooks--update
Fix potential command line overflow in hooks--update
[thirdparty/git.git] / templates / hooks--update
CommitLineData
8d5afef0
JH
1#!/bin/sh
2#
3# An example hook script to mail out commit update information.
829a686f 4# It can also blocks tags that aren't annotated.
c65a9470 5# Called by git-receive-pack with arguments: refname sha1-old sha1-new
8d5afef0 6#
829a686f 7# To enable this hook, make this file executable by "chmod +x update".
8d5afef0 8#
829a686f
AP
9# Config
10# ------
11# hooks.mailinglist
12# This is the list that all pushes will go to; leave it blank to not send
13# emails frequently. The log email will list every log entry in full between
14# the old ref value and the new ref value.
15# hooks.announcelist
16# This is the list that all pushes of annotated tags will go to. Leave it
17# blank to just use the mailinglist field. The announce emails list the
18# short log summary of the changes since the last annotated tag
19# hooks.allowunannotated
20# This boolean sets whether unannotated tags will be allowed into the
21# repository. By default they won't be.
22#
23# Notes
24# -----
25# All emails have their subjects prefixed with "[SCM]" to aid filtering.
26# All emails include the headers "X-Git-Refname", "X-Git-Oldrev",
27# "X-Git-Newrev", and "X-Git-Reftype" to enable fine tuned filtering and info.
8d5afef0 28
829a686f
AP
29# --- Constants
30EMAILPREFIX="[SCM] "
31LOGBEGIN="- Log -----------------------------------------------------------------"
32LOGEND="-----------------------------------------------------------------------"
33DATEFORMAT="%F %R %z"
34
35# --- Command line
36refname="$1"
37oldrev="$2"
38newrev="$3"
39
40# --- Safety check
41if [ -z "$GIT_DIR" ]; then
42 echo "Don't run this script from the command line." >&2
43 echo " (if you want, you could supply GIT_DIR then run" >&2
44 echo " $0 <ref> <oldrev> <newrev>)" >&2
45 exit 1
46fi
47
48if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
49 echo "Usage: $0 <ref> <oldrev> <newrev>" >&2
50 exit 1
51fi
52
53# --- Config
54projectdesc=$(cat $GIT_DIR/description)
55recipients=$(git-repo-config hooks.mailinglist)
56announcerecipients=$(git-repo-config hooks.announcelist)
57allowunannotated=$(git-repo-config --bool hooks.allowunannotated)
8a3ee7c3 58
829a686f
AP
59# --- Check types
60newrev_type=$(git-cat-file -t "$newrev")
61
62case "$refname","$newrev_type" in
63 refs/tags/*,commit)
3dff5379 64 # un-annotated tag
829a686f
AP
65 refname_type="tag"
66 short_refname=${refname##refs/tags/}
67 if [ $allowunannotated != "true" ]; then
68 echo "*** The un-annotated tag, $short_refname is not allowed in this repository" >&2
69 echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
70 exit 1
8a3ee7c3 71 fi
829a686f
AP
72 ;;
73 refs/tags/*,tag)
74 # annotated tag
75 refname_type="annotated tag"
76 short_refname=${refname##refs/tags/}
77 # change recipients
78 if [ -n "$announcerecipients" ]; then
79 recipients="$announcerecipients"
8a3ee7c3
AE
80 fi
81 ;;
829a686f
AP
82 refs/heads/*,commit)
83 # branch
84 refname_type="branch"
85 short_refname=${refname##refs/heads/}
86 ;;
87 refs/remotes/*,commit)
88 # tracking branch
89 refname_type="tracking branch"
90 short_refname=${refname##refs/remotes/}
91 # Should this even be allowed?
92 echo "*** Push-update of tracking branch, $refname. No email generated." >&2
93 exit 0
94 ;;
95 *)
96 # Anything else (is there anything else?)
97 echo "*** Update hook: unknown type of update, \"$newrev_type\", to ref $refname" >&2
98 exit 1
99 ;;
100esac
101
102# Check if we've got anyone to send to
103if [ -z "$recipients" ]; then
104 # If the email isn't sent, then at least give the user some idea of what command
105 # would generate the email at a later date
106 echo "*** No recipients found - no email will be sent, but the push will continue" >&2
107 echo "*** for $0 $1 $2 $3" >&2
108 exit 0
109fi
110
111# --- Email parameters
112committer=$(git show --pretty=full -s $newrev | grep "^Commit: " | sed -e "s/^Commit: //")
113describe=$(git describe $newrev 2>/dev/null)
114if [ -z "$describe" ]; then
115 describe=$newrev
116fi
8a3ee7c3 117
829a686f
AP
118# --- Email (all stdout will be the email)
119(
120# Generate header
121cat <<-EOF
122From: $committer
123To: $recipients
124Subject: ${EMAILPREFIX}$projectdesc $refname_type, $short_refname now at $describe
125X-Git-Refname: $refname
126X-Git-Reftype: $refname_type
127X-Git-Oldrev: $oldrev
128X-Git-Newrev: $newrev
129
130Hello,
131
132This is an automated email from the git hooks/update script, it was
133generated because a ref change was pushed to the repository.
134
135Updating $refname_type, $short_refname,
136EOF
137
138case "$refname_type" in
139 "tracking branch"|branch)
140 if expr "$oldrev" : '0*$' >/dev/null
141 then
142 # If the old reference is "0000..0000" then this is a new branch
143 # and so oldrev is not valid
144 echo " as a new $refname_type"
145 echo " to $newrev ($newrev_type)"
146 echo ""
147 echo $LOGBEGIN
148 # This shows all log entries that are not already covered by
149 # another ref - i.e. commits that are now accessible from this
150 # ref that were previously not accessible
72f627d2 151 git-rev-parse --not --all | git-rev-list --stdin --pretty $newref
829a686f
AP
152 echo $LOGEND
153 else
154 # oldrev is valid
155 oldrev_type=$(git-cat-file -t "$oldrev")
156
157 # Now the problem is for cases like this:
158 # * --- * --- * --- * (oldrev)
159 # \
160 # * --- * --- * (newrev)
161 # i.e. there is no guarantee that newrev is a strict subset
162 # of oldrev - (would have required a force, but that's allowed).
163 # So, we can't simply say rev-list $oldrev..$newrev. Instead
164 # we find the common base of the two revs and list from there
165 baserev=$(git-merge-base $oldrev $newrev)
166
167 # Commit with a parent
168 for rev in $(git-rev-list $newrev ^$baserev)
169 do
170 revtype=$(git-cat-file -t "$rev")
171 echo " via $rev ($revtype)"
172 done
173 if [ "$baserev" = "$oldrev" ]; then
174 echo " from $oldrev ($oldrev_type)"
175 else
176 echo " based on $baserev"
177 echo " from $oldrev ($oldrev_type)"
178 echo ""
179 echo "This ref update crossed a branch point; i.e. the old rev is not a strict subset"
180 echo "of the new rev. This occurs, when you --force push a change in a situation"
181 echo "like this:"
182 echo ""
183 echo " * -- * -- B -- O -- O -- O ($oldrev)"
184 echo " \\"
185 echo " N -- N -- N ($newrev)"
186 echo ""
187 echo "Therefore, we assume that you've already had alert emails for all of the O"
188 echo "revisions, and now give you all the revisions in the N branch from the common"
189 echo "base, B ($baserev), up to the new revision."
190 fi
191 echo ""
192 echo $LOGBEGIN
193 git-rev-list --pretty $newrev ^$baserev
194 echo $LOGEND
195 echo ""
196 echo "Diffstat:"
197 git-diff-tree --no-color --stat -M -C --find-copies-harder $newrev ^$baserev
198 fi
8a3ee7c3 199 ;;
829a686f
AP
200 "annotated tag")
201 # Should we allow changes to annotated tags?
202 if expr "$oldrev" : '0*$' >/dev/null
203 then
204 # If the old reference is "0000..0000" then this is a new atag
205 # and so oldrev is not valid
206 echo " to $newrev ($newrev_type)"
207 else
208 echo " to $newrev ($newrev_type)"
209 echo " from $oldrev"
210 fi
211
212 # If this tag succeeds another, then show which tag it replaces
213 prevtag=$(git describe $newrev^ 2>/dev/null | sed 's/-g.*//')
214 if [ -n "$prevtag" ]; then
215 echo " replaces $prevtag"
216 fi
217
218 # Read the tag details
219 eval $(git cat-file tag $newrev | \
220 sed -n '4s/tagger \([^>]*>\)[^0-9]*\([0-9]*\).*/tagger="\1" ts="\2"/p')
221 tagged=$(date --date="1970-01-01 00:00:00 +0000 $ts seconds" +"$DATEFORMAT")
222
223 echo " tagged by $tagger"
224 echo " on $tagged"
225
226 echo ""
227 echo $LOGBEGIN
228 echo ""
229
230 if [ -n "$prevtag" ]; then
231 git rev-list --pretty=short "$prevtag..$newrev" | git shortlog
232 else
233 git rev-list --pretty=short $newrev | git shortlog
234 fi
235
236 echo $LOGEND
237 echo ""
86b13da4
JH
238 ;;
239 *)
829a686f
AP
240 # By default, unannotated tags aren't allowed in; if
241 # they are though, it's debatable whether we would even want an
242 # email to be generated; however, I don't want to add another config
243 # option just for that.
244 #
245 # Unannotated tags are more about marking a point than releasing
246 # a version; therefore we don't do the shortlog summary that we
247 # do for annotated tags above - we simply show that the point has
248 # been marked, and print the log message for the marked point for
249 # reference purposes
250 #
251 # Note this section also catches any other reference type (although
252 # there aren't any) and deals with them in the same way.
253 if expr "$oldrev" : '0*$' >/dev/null
254 then
255 # If the old reference is "0000..0000" then this is a new tag
256 # and so oldrev is not valid
257 echo " as a new $refname_type"
258 echo " to $newrev ($newrev_type)"
259 else
260 echo " to $newrev ($newrev_type)"
261 echo " from $oldrev"
262 fi
263 echo ""
264 echo $LOGBEGIN
265 git-show --no-color --root -s $newrev
266 echo $LOGEND
267 echo ""
86b13da4 268 ;;
829a686f
AP
269esac
270
271# Footer
272cat <<-EOF
273
274hooks/update
275---
276Git Source Code Management System
277$0 $1 \\
278 $2 \\
279 $3
280EOF
281#) | cat >&2
282) | /usr/sbin/sendmail -t
283
284# --- Finished
8d5afef0 285exit 0