3 # An example hook script to mail out commit update information.
4 # It can also blocks tags that aren't annotated.
5 # Called by git-receive-pack with arguments: refname sha1-old sha1-new
7 # To enable this hook, make this file executable by "chmod +x update".
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.
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.
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.
31 LOGBEGIN
="- Log -----------------------------------------------------------------"
32 LOGEND
="-----------------------------------------------------------------------"
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
48 if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
49 echo "Usage: $0 <ref> <oldrev> <newrev>" >&2
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
)
60 newrev_type
=$
(git-cat-file
-t "$newrev")
62 case "$refname","$newrev_type" in
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
75 refname_type
="annotated tag"
76 short_refname
=${refname##refs/tags/}
78 if [ -n "$announcerecipients" ]; then
79 recipients
="$announcerecipients"
85 short_refname
=${refname##refs/heads/}
87 refs
/remotes
/*,commit
)
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
96 # Anything else (is there anything else?)
97 echo "*** Update hook: unknown type of update, \"$newrev_type\", to ref $refname" >&2
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
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
118 # --- Email (all stdout will be the email)
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
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.
135 Updating $refname_type, $short_refname,
138 case "$refname_type" in
139 "tracking branch"|branch
)
140 if expr "$oldrev" : '0*$' >/dev
/null
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)"
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
151 git-rev-parse
--not --all | git-rev-list
--stdin --pretty $newref
155 oldrev_type
=$
(git-cat-file
-t "$oldrev")
157 # Now the problem is for cases like this:
158 # * --- * --- * --- * (oldrev)
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)
167 # Commit with a parent
168 for rev in $
(git-rev-list
$newrev ^
$baserev)
170 revtype
=$
(git-cat-file
-t "$rev")
171 echo " via $rev ($revtype)"
173 if [ "$baserev" = "$oldrev" ]; then
174 echo " from $oldrev ($oldrev_type)"
176 echo " based on $baserev"
177 echo " from $oldrev ($oldrev_type)"
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"
183 echo " * -- * -- B -- O -- O -- O ($oldrev)"
185 echo " N -- N -- N ($newrev)"
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."
193 git-rev-parse
--not --all |
194 git-rev-list
--stdin --pretty $newrev ^
$baserev
198 git-diff-tree
--no-color --stat -M -C --find-copies-harder $newrev ^
$baserev
202 # Should we allow changes to annotated tags?
203 if expr "$oldrev" : '0*$' >/dev
/null
205 # If the old reference is "0000..0000" then this is a new atag
206 # and so oldrev is not valid
207 echo " to $newrev ($newrev_type)"
209 echo " to $newrev ($newrev_type)"
213 # If this tag succeeds another, then show which tag it replaces
214 prevtag
=$
(git describe
$newrev^
2>/dev
/null |
sed 's/-g.*//')
215 if [ -n "$prevtag" ]; then
216 echo " replaces $prevtag"
219 # Read the tag details
220 eval $
(git cat-file tag
$newrev | \
221 sed -n '4s/tagger \([^>]*>\)[^0-9]*\([0-9]*\).*/tagger="\1" ts="\2"/p')
222 tagged
=$
(date --date="1970-01-01 00:00:00 +0000 $ts seconds" +"$DATEFORMAT")
224 echo " tagged by $tagger"
231 if [ -n "$prevtag" ]; then
232 git rev-list
--pretty=short
"$prevtag..$newrev" | git shortlog
234 git rev-list
--pretty=short
$newrev | git shortlog
241 # By default, unannotated tags aren't allowed in; if
242 # they are though, it's debatable whether we would even want an
243 # email to be generated; however, I don't want to add another config
244 # option just for that.
246 # Unannotated tags are more about marking a point than releasing
247 # a version; therefore we don't do the shortlog summary that we
248 # do for annotated tags above - we simply show that the point has
249 # been marked, and print the log message for the marked point for
252 # Note this section also catches any other reference type (although
253 # there aren't any) and deals with them in the same way.
254 if expr "$oldrev" : '0*$' >/dev
/null
256 # If the old reference is "0000..0000" then this is a new tag
257 # and so oldrev is not valid
258 echo " as a new $refname_type"
259 echo " to $newrev ($newrev_type)"
261 echo " to $newrev ($newrev_type)"
266 git-show
--no-color --root -s $newrev
277 Git Source Code Management System
283 ) |
/usr
/sbin
/sendmail
-t