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 for no description 60if[-z"$projectdesc"-o"$projectdesc"="Unnamed repository; edit this file to name it for gitweb"];then 61echo"*** Project description file hasn't been set">&2 62exit1 63fi 64 65# --- Check types 66newrev_type=$(git-cat-file -t $newrev) 67 68case"$refname","$newrev_type"in 69 refs/tags/*,commit) 70# un-annotated tag 71 refname_type="tag" 72 short_refname=${refname##refs/tags/} 73if["$allowunannotated"!="true"];then 74echo"*** The un-annotated tag,$short_refnameis not allowed in this repository">&2 75echo"*** Use 'git tag [ -a | -s ]' for tags you want to propagate.">&2 76exit1 77fi 78;; 79 refs/tags/*,tag) 80# annotated tag 81 refname_type="annotated tag" 82 short_refname=${refname##refs/tags/} 83# change recipients 84if[-n"$announcerecipients"];then 85 recipients="$announcerecipients" 86fi 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? 98echo"*** Push-update of tracking branch,$refname. No email generated.">&2 99exit0 100;; 101*) 102# Anything else (is there anything else?) 103echo"*** Update hook: unknown type of update,\"$newrev_type\", to ref$refname">&2 104exit1 105;; 106esac 107 108# Check if we've got anyone to send to 109if[-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 112echo"*** No recipients found - no email will be sent, but the push will continue">&2 113echo"*** for$0$1$2$3">&2 114exit0 115fi 116 117# --- Email parameters 118committer=$(git show --pretty=full -s $newrev | grep "^Commit: " | sed -e "s/^Commit: //") 119describe=$(git describe $newrev 2>/dev/null) 120if[-z"$describe"];then 121 describe=$newrev 122fi 123 124# --- Email (all stdout will be the email) 125( 126# Generate header 127cat<<-EOF 128From:$committer 129To:$recipients 130Subject:${EMAILPREFIX}$projectdesc$refname_type,$short_refnamenow at$describe 131X-Git-Refname:$refname 132X-Git-Reftype:$refname_type 133X-Git-Oldrev:$oldrev 134X-Git-Newrev:$newrev 135 136Hello, 137 138This is an automated email from the git hooks/update script, it was 139generated because a ref change was pushed to the repository. 140 141Updating$refname_type,$short_refname, 142EOF 143 144case"$refname_type"in 145"tracking branch"|branch) 146ifexpr"$oldrev":'0*$'>/dev/null 147then 148# If the old reference is "0000..0000" then this is a new branch 149# and so oldrev is not valid 150echo" as a new$refname_type" 151echo" to$newrev($newrev_type)" 152echo"" 153echo$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 158echo$LOGEND 159else 160# oldrev is valid 161 oldrev_type=$(git-cat-file -t "$oldrev") 162 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) 172 173# Commit with a parent 174forrevin$(git-rev-list $newrev --not $baserev --all) 175do 176 revtype=$(git-cat-file -t "$rev") 177echo" via$rev($revtype)" 178done 179if["$baserev"="$oldrev"];then 180echo" from$oldrev($oldrev_type)" 181else 182echo" based on$baserev" 183echo" from$oldrev($oldrev_type)" 184echo"" 185echo"This ref update crossed a branch point; i.e. the old rev is not a strict subset" 186echo"of the new rev. This occurs, when you --force push a change in a situation" 187echo"like this:" 188echo"" 189echo" * -- * -- B -- O -- O -- O ($oldrev)" 190echo"\\" 191echo" N -- N -- N ($newrev)" 192echo"" 193echo"Therefore, we assume that you've already had alert emails for all of the O" 194echo"revisions, and now give you all the revisions in the N branch from the common" 195echo"base, B ($baserev), up to the new revision." 196fi 197echo"" 198echo$LOGBEGIN 199 git log $newrev--not$baserev--all 200echo$LOGEND 201echo"" 202echo"Diffstat:" 203 git-diff-tree --no-color --stat -M -C --find-copies-harder$baserev..$newrev 204fi 205;; 206"annotated tag") 207# Should we allow changes to annotated tags? 208ifexpr"$oldrev":'0*$'>/dev/null 209then 210# If the old reference is "0000..0000" then this is a new atag 211# and so oldrev is not valid 212echo" to$newrev($newrev_type)" 213else 214echo" to$newrev($newrev_type)" 215echo" from$oldrev" 216fi 217 218# If this tag succeeds another, then show which tag it replaces 219 prevtag=$(git describe --abbrev=0 $newrev^ 2>/dev/null) 220if[-n"$prevtag"];then 221echo" replaces$prevtag" 222fi 223 224# Read the tag details 225eval $(git cat-file tag $newrev| \ 226sed-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") 228 229echo" tagged by$tagger" 230echo" on$tagged" 231 232echo"" 233echo$LOGBEGIN 234echo"" 235 236if[-n"$prevtag"];then 237 git rev-list --pretty=short "$prevtag..$newrev"| git shortlog 238else 239 git rev-list --pretty=short $newrev| git shortlog 240fi 241 242echo$LOGEND 243echo"" 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. 259ifexpr"$oldrev":'0*$'>/dev/null 260then 261# If the old reference is "0000..0000" then this is a new tag 262# and so oldrev is not valid 263echo" as a new$refname_type" 264echo" to$newrev($newrev_type)" 265else 266echo" to$newrev($newrev_type)" 267echo" from$oldrev" 268fi 269echo"" 270echo$LOGBEGIN 271 git-show --no-color --root -s$newrev 272echo$LOGEND 273echo"" 274;; 275esac 276 277# Footer 278cat<<-EOF 279 280hooks/update 281--- 282Git Source Code Management System 283$0$1\\ 284$2\\ 285$3 286EOF 287#) | cat >&2 288) | /usr/sbin/sendmail -t 289 290# --- Finished 291exit0