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 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 42echo"Don't run this script from the command line.">&2 43echo" (if you want, you could supply GIT_DIR then run">&2 44echo"$0<ref> <oldrev> <newrev>)">&2 45exit1 46fi 47 48if[-z"$refname"-o -z"$oldrev"-o -z"$newrev"];then 49echo"Usage:$0<ref> <oldrev> <newrev>">&2 50exit1 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) 58 59# --- Check types 60newrev_type=$(git-cat-file -t $newrev) 61 62case"$refname","$newrev_type"in 63 refs/tags/*,commit) 64# un-annotated tag 65 refname_type="tag" 66 short_refname=${refname##refs/tags/} 67if["$allowunannotated"!="true"];then 68echo"*** The un-annotated tag,$short_refnameis not allowed in this repository">&2 69echo"*** Use 'git tag [ -a | -s ]' for tags you want to propagate.">&2 70exit1 71fi 72;; 73 refs/tags/*,tag) 74# annotated tag 75 refname_type="annotated tag" 76 short_refname=${refname##refs/tags/} 77# change recipients 78if[-n"$announcerecipients"];then 79 recipients="$announcerecipients" 80fi 81;; 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? 92echo"*** Push-update of tracking branch,$refname. No email generated.">&2 93exit0 94;; 95*) 96# Anything else (is there anything else?) 97echo"*** Update hook: unknown type of update,\"$newrev_type\", to ref$refname">&2 98exit1 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 106echo"*** No recipients found - no email will be sent, but the push will continue">&2 107echo"*** for$0$1$2$3">&2 108exit0 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 117 118# --- Email (all stdout will be the email) 119( 120# Generate header 121cat<<-EOF 122From:$committer 123To:$recipients 124Subject:${EMAILPREFIX}$projectdesc$refname_type,$short_refnamenow 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) 140ifexpr"$oldrev":'0*$'>/dev/null 141then 142# If the old reference is "0000..0000" then this is a new branch 143# and so oldrev is not valid 144echo" as a new$refname_type" 145echo" to$newrev($newrev_type)" 146echo"" 147echo$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 151 git log $newrev--not --all 152echo$LOGEND 153else 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 168forrevin$(git-rev-list $newrev --not $baserev --all) 169do 170 revtype=$(git-cat-file -t "$rev") 171echo" via$rev($revtype)" 172done 173if["$baserev"="$oldrev"];then 174echo" from$oldrev($oldrev_type)" 175else 176echo" based on$baserev" 177echo" from$oldrev($oldrev_type)" 178echo"" 179echo"This ref update crossed a branch point; i.e. the old rev is not a strict subset" 180echo"of the new rev. This occurs, when you --force push a change in a situation" 181echo"like this:" 182echo"" 183echo" * -- * -- B -- O -- O -- O ($oldrev)" 184echo"\\" 185echo" N -- N -- N ($newrev)" 186echo"" 187echo"Therefore, we assume that you've already had alert emails for all of the O" 188echo"revisions, and now give you all the revisions in the N branch from the common" 189echo"base, B ($baserev), up to the new revision." 190fi 191echo"" 192echo$LOGBEGIN 193 git log $newrev--not$baserev--all 194echo$LOGEND 195echo"" 196echo"Diffstat:" 197 git-diff-tree --no-color --stat -M -C --find-copies-harder$baserev..$newrev 198fi 199;; 200"annotated tag") 201# Should we allow changes to annotated tags? 202ifexpr"$oldrev":'0*$'>/dev/null 203then 204# If the old reference is "0000..0000" then this is a new atag 205# and so oldrev is not valid 206echo" to$newrev($newrev_type)" 207else 208echo" to$newrev($newrev_type)" 209echo" from$oldrev" 210fi 211 212# If this tag succeeds another, then show which tag it replaces 213 prevtag=$(git describe --abbrev=0 $newrev^ 2>/dev/null) 214if[-n"$prevtag"];then 215echo" replaces$prevtag" 216fi 217 218# Read the tag details 219eval $(git cat-file tag $newrev| \ 220sed-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 223echo" tagged by$tagger" 224echo" on$tagged" 225 226echo"" 227echo$LOGBEGIN 228echo"" 229 230if[-n"$prevtag"];then 231 git rev-list --pretty=short "$prevtag..$newrev"| git shortlog 232else 233 git rev-list --pretty=short $newrev| git shortlog 234fi 235 236echo$LOGEND 237echo"" 238;; 239*) 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. 253ifexpr"$oldrev":'0*$'>/dev/null 254then 255# If the old reference is "0000..0000" then this is a new tag 256# and so oldrev is not valid 257echo" as a new$refname_type" 258echo" to$newrev($newrev_type)" 259else 260echo" to$newrev($newrev_type)" 261echo" from$oldrev" 262fi 263echo"" 264echo$LOGBEGIN 265 git-show --no-color --root -s$newrev 266echo$LOGEND 267echo"" 268;; 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 285exit0