update 8.4 KB

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