]>
Commit | Line | Data |
---|---|---|
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 |
30 | EMAILPREFIX="[SCM] " | |
31 | LOGBEGIN="- Log -----------------------------------------------------------------" | |
32 | LOGEND="-----------------------------------------------------------------------" | |
33 | DATEFORMAT="%F %R %z" | |
34 | ||
35 | # --- Command line | |
36 | refname="$1" | |
37 | oldrev="$2" | |
38 | newrev="$3" | |
39 | ||
40 | # --- Safety check | |
41 | if [ -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 | |
46 | fi | |
47 | ||
48 | if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then | |
49 | echo "Usage: $0 <ref> <oldrev> <newrev>" >&2 | |
50 | exit 1 | |
51 | fi | |
52 | ||
53 | # --- Config | |
54 | projectdesc=$(cat $GIT_DIR/description) | |
55 | recipients=$(git-repo-config hooks.mailinglist) | |
56 | announcerecipients=$(git-repo-config hooks.announcelist) | |
57 | allowunannotated=$(git-repo-config --bool hooks.allowunannotated) | |
8a3ee7c3 | 58 | |
829a686f AP |
59 | # --- Check types |
60 | newrev_type=$(git-cat-file -t "$newrev") | |
61 | ||
62 | case "$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 | ;; | |
100 | esac | |
101 | ||
102 | # Check if we've got anyone to send to | |
103 | if [ -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 | |
109 | fi | |
110 | ||
111 | # --- Email parameters | |
112 | committer=$(git show --pretty=full -s $newrev | grep "^Commit: " | sed -e "s/^Commit: //") | |
113 | describe=$(git describe $newrev 2>/dev/null) | |
114 | if [ -z "$describe" ]; then | |
115 | describe=$newrev | |
116 | fi | |
8a3ee7c3 | 117 | |
829a686f AP |
118 | # --- Email (all stdout will be the email) |
119 | ( | |
120 | # Generate header | |
121 | cat <<-EOF | |
122 | From: $committer | |
123 | To: $recipients | |
124 | Subject: ${EMAILPREFIX}$projectdesc $refname_type, $short_refname now at $describe | |
125 | X-Git-Refname: $refname | |
126 | X-Git-Reftype: $refname_type | |
127 | X-Git-Oldrev: $oldrev | |
128 | X-Git-Newrev: $newrev | |
129 | ||
130 | Hello, | |
131 | ||
132 | This is an automated email from the git hooks/update script, it was | |
133 | generated because a ref change was pushed to the repository. | |
134 | ||
135 | Updating $refname_type, $short_refname, | |
136 | EOF | |
137 | ||
138 | case "$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 |
269 | esac |
270 | ||
271 | # Footer | |
272 | cat <<-EOF | |
273 | ||
274 | hooks/update | |
275 | --- | |
276 | Git Source Code Management System | |
277 | $0 $1 \\ | |
278 | $2 \\ | |
279 | $3 | |
280 | EOF | |
281 | #) | cat >&2 | |
282 | ) | /usr/sbin/sendmail -t | |
283 | ||
284 | # --- Finished | |
8d5afef0 | 285 | exit 0 |