1#!/bin/sh 2 3# This is a git pre-push hook script. 4# It limits what you can push toward https://github.com/erlang/otp.git 5# 6# To activate, make a copy as .git/hooks/pre-push in your repo. 7 8# Called by "git push" 9# after it has checked the remote status, but before anything has been 10# pushed. If this script exits with a non-zero status nothing will be pushed. 11# 12# This hook is called with the following parameters: 13# 14# $1 -- Name of the remote to which the push is being done 15# $2 -- URL to which the push is being done 16# 17# If pushing without using a named remote those arguments will be equal. 18# 19# Information about the commits which are being pushed is supplied as lines to 20# the standard input in the form: 21# 22# <local ref> <local sha1> <remote ref> <remote sha1> 23# 24 25# Bump this version to give users an update notification. 26PRE_PUSH_SCRIPT_VERSION=2 27 28NEW_RELEASES="23 22 21 20 19 18 17" 29OLD_RELEASES="r16 r15 r14 r13" 30RELEASES="$NEW_RELEASES $OLD_RELEASES" 31 32# First commit on master, not allowed in other branches 33MASTER_ONLY=740b29ecc21c73a4bf4ebfc494490865d3c31978 34 35# Number of commits and files allowed in one push by this script 36NCOMMITS_MAX=100 37NFILES_MAX=100 38 39 40# Example testing this script for "git push upstream OTP-20.3.8.2": 41# 42#> null=0000000000000000000000000000000000000000 43#> echo "refs/tags/OTP-20.3.8.2 dummysha refs/tags/OTP-20.3.8.2 $null" | scripts/pre-push upstream https://github.com/erlang/otp.git 44 45# Example to test "git push upstream master" 46# 47#> local_sha=`git rev-parse master` 48#> remote_sha=`git rev-parse upstream/master` 49#> echo "refs/heads/master $local_sha refs/heads/master $remote_sha" | scripts/pre-push upstream https://github.com/erlang/otp.git 50 51 52remote="$1" 53url="$2" 54 55null=0000000000000000000000000000000000000000 56 57#echo "pre-push hook: remote=$remote" 58#echo "pre-push hook: url=$url" 59 60red_on() { 61 printf '%b' "\033[31m" 62} 63 64red_off() { 65 printf '%b' "\033[0m" 66} 67 68if [ "$url" = 'https://github.com/erlang/otp.git' -o "$url" = 'git@github.com:erlang/otp.git' -o "$url" = 'git@github.com:erlang/otp' ] 69then 70 if [ $remote = "$url" ]; then 71 red_on 72 echo "$0 says:" 73 echo "***" 74 echo "*** Push to $url without using a named remote is NOT ALLOWED!!!!" 75 echo "***" 76 red_off 77 exit 1 78 fi 79 IFS=' ' 80 while read local_ref local_sha remote_ref remote_sha 81 do 82 #echo "pre-push hook: local_ref=$local_ref" 83 #echo "pre-push hook: remote_ref=$remote_ref" 84 #echo "pre-push hook: local_sha=$local_sha" 85 #echo "pre-push hook: remote_sha=$remote_sha" 86 87 if [ "$local_sha" = $null ] 88 then 89 red_on 90 echo "$0 says:" 91 echo "***" 92 echo "*** DELETE push to '$remote' NOT ALLOWED!!!!!" 93 echo "***" 94 red_off 95 exit 1 96 fi 97 if [ "$local_ref" != "$remote_ref" ] 98 then 99 red_on 100 echo "$0 says:" 101 echo "***" 102 echo "*** RENAME push: $local_ref pushed as $remote_ref to '$remote' NOT ALLOWED!!!!" 103 echo "***" 104 red_off 105 exit 1 106 fi 107 case "$remote_ref" in 108 refs/heads/master | refs/heads/maint | refs/heads/maint-[0-9][0-9] | refs/heads/maint-r[0-9][0-9]) 109 branch=${remote_ref#refs/heads/} 110 if [ "$remote_sha" = $null ] 111 then 112 red_on 113 echo "$0 says:" 114 echo "***" 115 echo "*** UNKNOWN BRANCH: '$branch' does not exist at '$remote'!!!!" 116 echo "***" 117 red_off 118 exit 1 119 fi 120 if ! git log -1 --oneline $remote_sha > /dev/null 2>&1 121 then 122 red_on 123 echo "$0 says:" 124 echo "***" 125 echo "*** The top of '$branch' at '$remote' ($remote_sha)" 126 echo "*** does not exist locally!!!" 127 echo "*** You probably need to refresh local '$branch' and redo merge." 128 echo "***" 129 red_off 130 exit 1 131 fi 132 if ! git merge-base --is-ancestor $remote_sha $local_sha 133 then 134 red_on 135 echo "$0 says:" 136 echo "***" 137 echo "*** FORCE push branch to '$remote' NOT ALLOWED!!!" 138 echo "***" 139 red_off 140 exit 1 141 fi 142 if [ $remote_ref != refs/heads/master -a "$MASTER_ONLY" ] && git merge-base --is-ancestor $MASTER_ONLY $local_sha 143 then 144 THIS_SCRIPT=`git rev-parse --git-path hooks/pre-push` 145 THIS_SCRIPT=`realpath $THIS_SCRIPT` 146 if git show refs/remotes/$remote/master:scripts/pre-push | diff -q --context=0 $THIS_SCRIPT - > /dev/null 2>&1 147 then 148 red_on 149 echo "$0 says:" 150 echo "***" 151 echo "*** INVALID MERGE: Commit $MASTER_ONLY should not be reachable from '$branch'!!!!" 152 echo "*** You have probably merged master into '$branch' by mistake" 153 echo "***" 154 red_off 155 exit 1 156 else 157 red_on 158 echo "$0 says:" 159 echo "***" 160 echo "*** The pre-push hook of this OTP repo needs updating." 161 echo "*** Do it by executing the following command:" 162 echo "***" 163 echo "*** git show refs/remotes/$remote/master:scripts/pre-push > $THIS_SCRIPT" 164 echo "***" 165 echo "*** And then retry the push." 166 echo "***" 167 red_off 168 exit 1 169 fi 170 fi 171 if [ ${remote_ref#refs/heads/maint-} != $remote_ref ] && git merge-base --is-ancestor refs/remotes/$remote/maint $local_sha 172 then 173 red_on 174 echo "$0 says:" 175 echo "***" 176 echo "*** INVALID MERGE: Branch maint should not be reachable from '$branch'!!!!" 177 echo "*** You have probably merged maint into '$branch' by mistake." 178 echo "***" 179 red_off 180 exit 1 181 fi 182 if [ $remote_ref = refs/heads/maint -o $remote_ref = refs/heads/master ]; then 183 for x in $RELEASES; do 184 if ! git merge-base --is-ancestor refs/remotes/$remote/maint-$x $local_sha; then 185 echo "$0 says:" 186 echo "***" 187 echo "*** WARNING: Branch '$remote/maint-$x' is not reachable from '$branch'!!!!" 188 echo "*** Someone needs to merge 'maint-$x' forward and push." 189 echo "***" 190 fi 191 done 192 fi 193 if [ $remote_ref = refs/heads/master ] && ! git merge-base --is-ancestor refs/remotes/$remote/maint $local_sha 194 then 195 red_on 196 echo "$0 says:" 197 echo "***" 198 echo "*** INVALID PUSH: Branch '$remote/maint' is not reachable from master!!!!" 199 echo "*** Someone needs to merge maint forward to master and push." 200 echo "***" 201 red_off 202 exit 1 203 fi 204 NCOMMITS=`git rev-list --count $remote_sha..$local_sha` 205 if [ $NCOMMITS -gt $NCOMMITS_MAX ] 206 then 207 red_on 208 echo "$0 says:" 209 echo "***" 210 echo "*** HUGE push: $NCOMMITS commits (> $NCOMMITS_MAX) to '$branch' at '$remote' NOT ALLOWED!!!!" 211 echo "***" 212 red_off 213 exit 1 214 fi 215 NFILES=`git diff --name-only $remote_sha $local_sha | wc --lines` 216 if [ $NFILES -gt $NFILES_MAX ] 217 then 218 red_on 219 echo "$0 says:" 220 echo "***" 221 echo "*** HUGE push: $NFILES changed files (> $NFILES_MAX) to '$branch' at '$remote' NOT ALLOWED!!!!" 222 echo "***" 223 red_off 224 exit 1 225 fi 226 ;; 227 refs/tags/OTP-*) 228 tag=${remote_ref#refs/tags/} 229 REL="UNKNOWN" 230 for x in $NEW_RELEASES; do 231 if [ ${tag#OTP-$x.} != $tag ] 232 then 233 REL=$x 234 break 235 fi 236 done 237 if [ $REL = "UNKNOWN" ] 238 then 239 red_on 240 echo "$0 says:" 241 echo "***" 242 echo "*** Unknown OTP release number in tag '$tag'" 243 echo "***" 244 red_off 245 exit 1 246 fi 247 if [ "$remote_sha" != $null ] 248 then 249 red_on 250 echo "$0 says:" 251 echo "***" 252 echo "*** FORCE push tag to '$remote' NOT ALLOWED!!!" 253 echo "*** Tag '$tag' already exists at '$remote'." 254 echo "***" 255 red_off 256 exit 1 257 fi 258 ;; 259 refs/heads/*) 260 branch=${remote_ref#refs/heads/} 261 red_on 262 echo "$0 says:" 263 echo "***" 264 echo "*** UNKNOWN branch name: '$branch' pushed to '$remote' NOT ALLOWED!!!!" 265 echo "***" 266 red_off 267 exit 1 268 ;; 269 refs/tags/*) 270 tag=${remote_ref#refs/tags/} 271 red_on 272 echo "$0 says:" 273 echo "***" 274 echo "*** UNKNOWN tag name: '$tag' pushed to '$remote' NOT ALLOWED!!!!" 275 echo "***" 276 red_off 277 exit 1 278 ;; 279 *) 280 red_on 281 echo "$0 says:" 282 echo "***" 283 echo "*** STRANGE ref: '$remote_ref' pushed to '$remote' NOT ALLOWED!!!!" 284 echo "***" 285 red_off 286 exit 1 287 ;; 288 esac 289 done 290 291 echo "$0: OK" 292 293 THIS_SCRIPT=`git rev-parse --git-path hooks/pre-push` 294 THIS_SCRIPT=`realpath $THIS_SCRIPT` 295 if git show refs/remotes/$remote/master:scripts/pre-push | diff --context=0 $THIS_SCRIPT - | grep -q PRE_PUSH_SCRIPT_VERSION > /dev/null 2>&1 296 then 297 echo "" 298 echo "NOTE: There is a newer version of the pre-push hook in this OTP repo." 299 echo " You can install it by executing the following command:" 300 echo 301 echo " git show refs/remotes/$remote/master:scripts/pre-push > $THIS_SCRIPT" 302 echo 303 fi 304else 305 echo "$0: No checks done for remote '$remote' at $url." 306fi 307 308exit 0 309 310