123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- #!/bin/sh
- #
- # An example hook script to mail out commit update information.
- # It can also blocks tags that aren't annotated.
- # Called by git-receive-pack with arguments: refname sha1-old sha1-new
- #
- # To enable this hook, make this file executable by "chmod +x update".
- #
- # Config
- # ------
- # hooks.mailinglist
- # This is the list that all pushes will go to; leave it blank to not send
- # emails frequently. The log email will list every log entry in full between
- # the old ref value and the new ref value.
- # hooks.announcelist
- # This is the list that all pushes of annotated tags will go to. Leave it
- # blank to just use the mailinglist field. The announce emails list the
- # short log summary of the changes since the last annotated tag
- # hooks.allowunannotated
- # This boolean sets whether unannotated tags will be allowed into the
- # repository. By default they won't be.
- #
- # Notes
- # -----
- # All emails have their subjects prefixed with "[SCM]" to aid filtering.
- # All emails include the headers "X-Git-Refname", "X-Git-Oldrev",
- # "X-Git-Newrev", and "X-Git-Reftype" to enable fine tuned filtering and info.
- # --- Constants
- EMAILPREFIX="[SCM] "
- LOGBEGIN="- Log -----------------------------------------------------------------"
- LOGEND="-----------------------------------------------------------------------"
- DATEFORMAT="%F %R %z"
- # --- Command line
- refname="$1"
- oldrev="$2"
- newrev="$3"
- # --- Safety check
- if [ -z "$GIT_DIR" ]; then
- echo "Don't run this script from the command line." >&2
- echo " (if you want, you could supply GIT_DIR then run" >&2
- echo " $0 <ref> <oldrev> <newrev>)" >&2
- exit 1
- fi
- if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
- echo "Usage: $0 <ref> <oldrev> <newrev>" >&2
- exit 1
- fi
- # --- Config
- projectdesc=$(cat $GIT_DIR/description)
- recipients=$(git-repo-config hooks.mailinglist)
- announcerecipients=$(git-repo-config hooks.announcelist)
- allowunannotated=$(git-repo-config --bool hooks.allowunannotated)
- # --- Check types
- newrev_type=$(git-cat-file -t "$newrev")
- case "$refname","$newrev_type" in
- refs/tags/*,commit)
- # un-annotated tag
- refname_type="tag"
- short_refname=${refname##refs/tags/}
- if [ "$allowunannotated" != "true" ]; then
- echo "*** The un-annotated tag, $short_refname is not allowed in this repository" >&2
- echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
- exit 1
- fi
- ;;
- refs/tags/*,tag)
- # annotated tag
- refname_type="annotated tag"
- short_refname=${refname##refs/tags/}
- # change recipients
- if [ -n "$announcerecipients" ]; then
- recipients="$announcerecipients"
- fi
- ;;
- refs/heads/*,commit)
- # branch
- refname_type="branch"
- short_refname=${refname##refs/heads/}
- ;;
- refs/remotes/*,commit)
- # tracking branch
- refname_type="tracking branch"
- short_refname=${refname##refs/remotes/}
- # Should this even be allowed?
- echo "*** Push-update of tracking branch, $refname. No email generated." >&2
- exit 0
- ;;
- *)
- # Anything else (is there anything else?)
- echo "*** Update hook: unknown type of update, \"$newrev_type\", to ref $refname" >&2
- exit 1
- ;;
- esac
- # Check if we've got anyone to send to
- if [ -z "$recipients" ]; then
- # If the email isn't sent, then at least give the user some idea of what command
- # would generate the email at a later date
- echo "*** No recipients found - no email will be sent, but the push will continue" >&2
- echo "*** for $0 $1 $2 $3" >&2
- exit 0
- fi
- # --- Email parameters
- committer=$(git show --pretty=full -s $newrev | grep "^Commit: " | sed -e "s/^Commit: //")
- describe=$(git describe $newrev 2>/dev/null)
- if [ -z "$describe" ]; then
- describe=$newrev
- fi
- # --- Email (all stdout will be the email)
- (
- # Generate header
- cat <<-EOF
- From: $committer
- To: $recipients
- Subject: ${EMAILPREFIX}$projectdesc $refname_type, $short_refname now at $describe
- X-Git-Refname: $refname
- X-Git-Reftype: $refname_type
- X-Git-Oldrev: $oldrev
- X-Git-Newrev: $newrev
- Hello,
- This is an automated email from the git hooks/update script, it was
- generated because a ref change was pushed to the repository.
- Updating $refname_type, $short_refname,
- EOF
- case "$refname_type" in
- "tracking branch"|branch)
- if expr "$oldrev" : '0*$' >/dev/null
- then
- # If the old reference is "0000..0000" then this is a new branch
- # and so oldrev is not valid
- echo " as a new $refname_type"
- echo " to $newrev ($newrev_type)"
- echo ""
- echo $LOGBEGIN
- # This shows all log entries that are not already covered by
- # another ref - i.e. commits that are now accessible from this
- # ref that were previously not accessible
- git-rev-parse --not --all | git-rev-list --stdin --pretty $newref
- echo $LOGEND
- else
- # oldrev is valid
- oldrev_type=$(git-cat-file -t "$oldrev")
- # Now the problem is for cases like this:
- # * --- * --- * --- * (oldrev)
- # \
- # * --- * --- * (newrev)
- # i.e. there is no guarantee that newrev is a strict subset
- # of oldrev - (would have required a force, but that's allowed).
- # So, we can't simply say rev-list $oldrev..$newrev. Instead
- # we find the common base of the two revs and list from there
- baserev=$(git-merge-base $oldrev $newrev)
- # Commit with a parent
- for rev in $(git-rev-list $newrev ^$baserev)
- do
- revtype=$(git-cat-file -t "$rev")
- echo " via $rev ($revtype)"
- done
- if [ "$baserev" = "$oldrev" ]; then
- echo " from $oldrev ($oldrev_type)"
- else
- echo " based on $baserev"
- echo " from $oldrev ($oldrev_type)"
- echo ""
- echo "This ref update crossed a branch point; i.e. the old rev is not a strict subset"
- echo "of the new rev. This occurs, when you --force push a change in a situation"
- echo "like this:"
- echo ""
- echo " * -- * -- B -- O -- O -- O ($oldrev)"
- echo " \\"
- echo " N -- N -- N ($newrev)"
- echo ""
- echo "Therefore, we assume that you've already had alert emails for all of the O"
- echo "revisions, and now give you all the revisions in the N branch from the common"
- echo "base, B ($baserev), up to the new revision."
- fi
- echo ""
- echo $LOGBEGIN
- git-rev-list --pretty $newrev ^$baserev
- echo $LOGEND
- echo ""
- echo "Diffstat:"
- git-diff-tree --no-color --stat -M -C --find-copies-harder $newrev ^$baserev
- fi
- ;;
- "annotated tag")
- # Should we allow changes to annotated tags?
- if expr "$oldrev" : '0*$' >/dev/null
- then
- # If the old reference is "0000..0000" then this is a new atag
- # and so oldrev is not valid
- echo " to $newrev ($newrev_type)"
- else
- echo " to $newrev ($newrev_type)"
- echo " from $oldrev"
- fi
- # If this tag succeeds another, then show which tag it replaces
- prevtag=$(git describe $newrev^ 2>/dev/null | sed 's/-g.*//')
- if [ -n "$prevtag" ]; then
- echo " replaces $prevtag"
- fi
- # Read the tag details
- eval $(git cat-file tag $newrev | \
- sed -n '4s/tagger \([^>]*>\)[^0-9]*\([0-9]*\).*/tagger="\1" ts="\2"/p')
- tagged=$(date --date="1970-01-01 00:00:00 +0000 $ts seconds" +"$DATEFORMAT")
- echo " tagged by $tagger"
- echo " on $tagged"
- echo ""
- echo $LOGBEGIN
- echo ""
- if [ -n "$prevtag" ]; then
- git rev-list --pretty=short "$prevtag..$newrev" | git shortlog
- else
- git rev-list --pretty=short $newrev | git shortlog
- fi
- echo $LOGEND
- echo ""
- ;;
- *)
- # By default, unannotated tags aren't allowed in; if
- # they are though, it's debatable whether we would even want an
- # email to be generated; however, I don't want to add another config
- # option just for that.
- #
- # Unannotated tags are more about marking a point than releasing
- # a version; therefore we don't do the shortlog summary that we
- # do for annotated tags above - we simply show that the point has
- # been marked, and print the log message for the marked point for
- # reference purposes
- #
- # Note this section also catches any other reference type (although
- # there aren't any) and deals with them in the same way.
- if expr "$oldrev" : '0*$' >/dev/null
- then
- # If the old reference is "0000..0000" then this is a new tag
- # and so oldrev is not valid
- echo " as a new $refname_type"
- echo " to $newrev ($newrev_type)"
- else
- echo " to $newrev ($newrev_type)"
- echo " from $oldrev"
- fi
- echo ""
- echo $LOGBEGIN
- git-show --no-color --root -s $newrev
- echo $LOGEND
- echo ""
- ;;
- esac
- # Footer
- cat <<-EOF
- hooks/update
- ---
- Git Source Code Management System
- $0 $1 \\
- $2 \\
- $3
- EOF
- #) | cat >&2
- ) | /usr/sbin/sendmail -t
- # --- Finished
- exit 0
|