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-rev-parse --not --all| git-rev-list --stdin --pretty$newref 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-parse --not --all | git-rev-list --stdin $newrev ^$baserev) 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-rev-parse --not --all| 194 git-rev-list --stdin --pretty$newrev ^$baserev 195echo$LOGEND 196echo"" 197echo"Diffstat:" 198 git-diff-tree --no-color --stat -M -C --find-copies-harder$newrev ^$baserev 199fi 200;; 201"annotated tag") 202# Should we allow changes to annotated tags? 203ifexpr"$oldrev":'0*$'>/dev/null 204then 205# If the old reference is "0000..0000" then this is a new atag 206# and so oldrev is not valid 207echo" to$newrev($newrev_type)" 208else 209echo" to$newrev($newrev_type)" 210echo" from$oldrev" 211fi 212 213# If this tag succeeds another, then show which tag it replaces 214 prevtag=$(git describe $newrev^ 2>/dev/null | sed 's/-g.*//') 215if[-n"$prevtag"];then 216echo" replaces$prevtag" 217fi 218 219# Read the tag details 220eval $(git cat-file tag $newrev| \ 221sed-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") 223 224echo" tagged by$tagger" 225echo" on$tagged" 226 227echo"" 228echo$LOGBEGIN 229echo"" 230 231if[-n"$prevtag"];then 232 git rev-list --pretty=short "$prevtag..$newrev"| git shortlog 233else 234 git rev-list --pretty=short $newrev| git shortlog 235fi 236 237echo$LOGEND 238echo"" 239;; 240*) 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. 245# 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 250# reference purposes 251# 252# Note this section also catches any other reference type (although 253# there aren't any) and deals with them in the same way. 254ifexpr"$oldrev":'0*$'>/dev/null 255then 256# If the old reference is "0000..0000" then this is a new tag 257# and so oldrev is not valid 258echo" as a new$refname_type" 259echo" to$newrev($newrev_type)" 260else 261echo" to$newrev($newrev_type)" 262echo" from$oldrev" 263fi 264echo"" 265echo$LOGBEGIN 266 git-show --no-color --root -s$newrev 267echo$LOGEND 268echo"" 269;; 270esac 271 272# Footer 273cat<<-EOF 274 275hooks/update 276--- 277Git Source Code Management System 278$0$1\\ 279$2\\ 280$3 281EOF 282#) | cat >&2 283) | /usr/sbin/sendmail -t 284 285# --- Finished 286exit0