Code

Merge branch 'master' into jc/bisect
[git.git] / templates / hooks--update
1 #!/bin/sh
2 #
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
6 #
7 # To enable this hook, make this file executable by "chmod +x update".
8 #
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.
29 # --- Constants
30 EMAILPREFIX="[SCM] "
31 LOGBEGIN="- Log -----------------------------------------------------------------"
32 LOGEND="-----------------------------------------------------------------------"
33 DATEFORMAT="%F %R %z"
35 # --- Command line
36 refname="$1"
37 oldrev="$2"
38 newrev="$3"
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
48 if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
49         echo "Usage: $0 <ref> <oldrev> <newrev>" >&2
50         exit 1
51 fi
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)
59 # check for no description
60 if [ -z "$projectdesc" -o "$projectdesc" = "Unnamed repository; edit this file to name it for gitweb" ]; then
61         echo "*** Project description file hasn't been set" >&2
62         exit 1
63 fi
65 # --- Check types
66 newrev_type=$(git-cat-file -t $newrev)
68 case "$refname","$newrev_type" in
69         refs/tags/*,commit)
70                 # un-annotated tag
71                 refname_type="tag"
72                 short_refname=${refname##refs/tags/}
73                 if [ "$allowunannotated" != "true" ]; then
74                         echo "*** The un-annotated tag, $short_refname is not allowed in this repository" >&2
75                         echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
76                         exit 1
77                 fi
78                 ;;
79         refs/tags/*,tag)
80                 # annotated tag
81                 refname_type="annotated tag"
82                 short_refname=${refname##refs/tags/}
83                 # change recipients
84                 if [ -n "$announcerecipients" ]; then
85                         recipients="$announcerecipients"
86                 fi
87                 ;;
88         refs/heads/*,commit)
89                 # branch
90                 refname_type="branch"
91                 short_refname=${refname##refs/heads/}
92                 ;;
93         refs/remotes/*,commit)
94                 # tracking branch
95                 refname_type="tracking branch"
96                 short_refname=${refname##refs/remotes/}
97                 # Should this even be allowed?
98                 echo "*** Push-update of tracking branch, $refname.  No email generated." >&2
99                 exit 0
100                 ;;
101         *)
102                 # Anything else (is there anything else?)
103                 echo "*** Update hook: unknown type of update, \"$newrev_type\", to ref $refname" >&2
104                 exit 1
105                 ;;
106 esac
108 # Check if we've got anyone to send to
109 if [ -z "$recipients" ]; then
110         # If the email isn't sent, then at least give the user some idea of what command
111         # would generate the email at a later date
112         echo "*** No recipients found - no email will be sent, but the push will continue" >&2
113         echo "*** for $0 $1 $2 $3" >&2
114         exit 0
115 fi
117 # --- Email parameters
118 committer=$(git show --pretty=full -s $newrev | grep "^Commit: " | sed -e "s/^Commit: //")
119 describe=$(git describe $newrev 2>/dev/null)
120 if [ -z "$describe" ]; then
121         describe=$newrev
122 fi
124 # --- Email (all stdout will be the email)
126 # Generate header
127 cat <<-EOF
128 From: $committer
129 To: $recipients
130 Subject: ${EMAILPREFIX}$projectdesc $refname_type, $short_refname now at $describe
131 X-Git-Refname: $refname
132 X-Git-Reftype: $refname_type
133 X-Git-Oldrev: $oldrev
134 X-Git-Newrev: $newrev
136 Hello,
138 This is an automated email from the git hooks/update script, it was
139 generated because a ref change was pushed to the repository.
141 Updating $refname_type, $short_refname,
142 EOF
144 case "$refname_type" in
145         "tracking branch"|branch)
146                 if expr "$oldrev" : '0*$' >/dev/null
147                 then
148                         # If the old reference is "0000..0000" then this is a new branch
149                         # and so oldrev is not valid
150                         echo "  as a new  $refname_type"
151                     echo "        to  $newrev ($newrev_type)"
152                         echo ""
153                         echo $LOGBEGIN
154                         # This shows all log entries that are not already covered by
155                         # another ref - i.e. commits that are now accessible from this
156                         # ref that were previously not accessible
157                         git log $newrev --not --all
158                         echo $LOGEND
159                 else
160                         # oldrev is valid
161                         oldrev_type=$(git-cat-file -t "$oldrev")
163                         # Now the problem is for cases like this:
164                         #   * --- * --- * --- * (oldrev)
165                         #          \
166                         #           * --- * --- * (newrev)
167                         # i.e. there is no guarantee that newrev is a strict subset
168                         # of oldrev - (would have required a force, but that's allowed).
169                         # So, we can't simply say rev-list $oldrev..$newrev.  Instead
170                         # we find the common base of the two revs and list from there
171                         baserev=$(git-merge-base $oldrev $newrev)
173                         # Commit with a parent
174                         for rev in $(git-rev-list $newrev --not $baserev --all)
175                         do
176                                 revtype=$(git-cat-file -t "$rev")
177                                 echo "       via  $rev ($revtype)"
178                         done
179                         if [ "$baserev" = "$oldrev" ]; then
180                                 echo "      from  $oldrev ($oldrev_type)"
181                         else
182                                 echo "  based on  $baserev"
183                                 echo "      from  $oldrev ($oldrev_type)"
184                                 echo ""
185                                 echo "This ref update crossed a branch point; i.e. the old rev is not a strict subset"
186                                 echo "of the new rev.  This occurs, when you --force push a change in a situation"
187                                 echo "like this:"
188                                 echo ""
189                                 echo " * -- * -- B -- O -- O -- O ($oldrev)"
190                                 echo "            \\"
191                                 echo "             N -- N -- N ($newrev)"
192                                 echo ""
193                                 echo "Therefore, we assume that you've already had alert emails for all of the O"
194                                 echo "revisions, and now give you all the revisions in the N branch from the common"
195                                 echo "base, B ($baserev), up to the new revision."
196                         fi
197                         echo ""
198                         echo $LOGBEGIN
199                         git log $newrev --not $baserev --all
200                         echo $LOGEND
201                         echo ""
202                         echo "Diffstat:"
203                         git-diff-tree --no-color --stat -M -C --find-copies-harder $baserev..$newrev
204                 fi
205                 ;;
206         "annotated tag")
207                 # Should we allow changes to annotated tags?
208                 if expr "$oldrev" : '0*$' >/dev/null
209                 then
210                         # If the old reference is "0000..0000" then this is a new atag
211                         # and so oldrev is not valid
212                         echo "        to  $newrev ($newrev_type)"
213                 else
214                         echo "        to  $newrev ($newrev_type)"
215                         echo "      from  $oldrev"
216                 fi
218                 # If this tag succeeds another, then show which tag it replaces
219                 prevtag=$(git describe --abbrev=0 $newrev^ 2>/dev/null)
220                 if [ -n "$prevtag" ]; then
221                         echo "  replaces  $prevtag"
222                 fi
224                 # Read the tag details
225                 eval $(git cat-file tag $newrev | \
226                         sed -n '4s/tagger \([^>]*>\)[^0-9]*\([0-9]*\).*/tagger="\1" ts="\2"/p')
227                 tagged=$(date --date="1970-01-01 00:00:00 +0000 $ts seconds" +"$DATEFORMAT")
229                 echo " tagged by  $tagger"
230                 echo "        on  $tagged"
232                 echo ""
233                 echo $LOGBEGIN
234                 echo ""
236                 if [ -n "$prevtag" ]; then
237                         git rev-list --pretty=short "$prevtag..$newrev" | git shortlog
238                 else
239                         git rev-list --pretty=short $newrev | git shortlog
240                 fi
242                 echo $LOGEND
243                 echo ""
244                 ;;
245         *)
246                 # By default, unannotated tags aren't allowed in; if
247                 # they are though, it's debatable whether we would even want an
248                 # email to be generated; however, I don't want to add another config
249                 # option just for that.
250                 #
251                 # Unannotated tags are more about marking a point than releasing
252                 # a version; therefore we don't do the shortlog summary that we
253                 # do for annotated tags above - we simply show that the point has
254                 # been marked, and print the log message for the marked point for
255                 # reference purposes
256                 #
257                 # Note this section also catches any other reference type (although
258                 # there aren't any) and deals with them in the same way.
259                 if expr "$oldrev" : '0*$' >/dev/null
260                 then
261                         # If the old reference is "0000..0000" then this is a new tag
262                         # and so oldrev is not valid
263                         echo "  as a new  $refname_type"
264                         echo "        to  $newrev ($newrev_type)"
265                 else
266                         echo "        to  $newrev ($newrev_type)"
267                         echo "      from  $oldrev"
268                 fi
269                 echo ""
270                 echo $LOGBEGIN
271                 git-show --no-color --root -s $newrev
272                 echo $LOGEND
273                 echo ""
274                 ;;
275 esac
277 # Footer
278 cat <<-EOF
280 hooks/update
281 ---
282 Git Source Code Management System
283 $0 $1 \\
284   $2 \\
285   $3
286 EOF
287 #) | cat >&2
288 ) | /usr/sbin/sendmail -t
290 # --- Finished
291 exit 0