pre-push.git-hook (4625B)
1 #!/usr/bin/env bash 2 3 # git pre-push hook script to: 4 # 0) Call the pre-commit hook, if it is available 5 # 1) prevent "fixup!" and "squash!" commit from ending up in main, release-* 6 # or maint-* 7 # 2) Disallow pushing branches other than main, release-* 8 # and maint-* to origin (e.g. gitweb.torproject.org) 9 # 10 # To install this script, copy it into .git/hooks/pre-push path in your 11 # local copy of git repository. Make sure it has permission to execute. 12 # Furthermore, make sure that TOR_UPSTREAM_REMOTE_NAME environment 13 # variable is set to local name of git remote that corresponds to upstream 14 # repository on e.g. git.torproject.org. 15 # 16 # The following sample script was used as starting point: 17 # https://github.com/git/git/blob/master/templates/hooks--pre-push.sample 18 19 # Are you adding a new check to the git hooks? 20 # - Common checks belong in the pre-commit hook 21 # - Push-only checks belong in the pre-push hook 22 23 echo "Running pre-push hook" 24 25 z40=0000000000000000000000000000000000000000 26 27 upstream_name=${TOR_UPSTREAM_REMOTE_NAME:-"upstream"} 28 29 # The working directory 30 workdir=$(git rev-parse --show-toplevel) 31 # The .git directory 32 # If $workdir is a worktree, then $gitdir is not $workdir/.git 33 gitdir=$(git rev-parse --git-dir) 34 35 cd "$workdir" || exit 1 36 37 remote="$1" 38 remote_name=$(git remote --verbose | grep "$2" | awk '{print $1}' | head -n 1) 39 40 41 ref_is_upstream_branch() { 42 if [ "$1" == "refs/heads/main" ] || 43 [[ "$1" == refs/heads/release-* ]] || 44 [[ "$1" == refs/heads/maint-* ]]; then 45 return 1 46 fi 47 } 48 49 # shellcheck disable=SC2034 50 while read -r local_ref local_sha remote_ref remote_sha 51 do 52 if [ "$local_sha" = $z40 ]; then 53 # Handle delete 54 : 55 else 56 if [ "$remote_sha" = $z40 ]; then 57 # New branch, examine commits not in main 58 range="main...$local_sha" 59 else 60 # Update to existing branch, examine new commits 61 range="$remote_sha..$local_sha" 62 fi 63 64 # Call the pre-commit hook for the common checks, if it is executable 65 pre_commit=${gitdir}/hooks/pre-commit 66 if [ -x "$pre_commit" ]; then 67 # Only check the files newly modified in this branch 68 CHECK_FILTER="git diff --name-only --diff-filter=ACMR $range" 69 # Use the appropriate owned tor source list to filter the changed 70 # files 71 # This is the layout in 0.3.5 72 # Keep these lists consistent: 73 # - OWNED_TOR_C_FILES in Makefile.am 74 # - CHECK_FILES in pre-commit.git-hook and pre-push.git-hook 75 # - try_parse in check_cocci_parse.sh 76 CHECK_FILES="$($CHECK_FILTER \ 77 src/lib/*/*.[ch] \ 78 src/core/*/*.[ch] \ 79 src/feature/*/*.[ch] \ 80 src/app/*/*.[ch] \ 81 src/test/*.[ch] \ 82 src/test/*/*.[ch] \ 83 src/tools/*.[ch] \ 84 )" 85 86 export TOR_EXTRA_PRE_COMMIT_CHECKS=1 87 # We want word splitting here, because file names are space 88 # separated 89 # shellcheck disable=SC2086 90 if ! "$pre_commit" $CHECK_FILES ; then 91 exit 1 92 fi 93 fi 94 95 if [[ "$remote_name" != "$upstream_name" ]]; then 96 echo "Not pushing to upstream - refraining from further checks" 97 continue 98 fi 99 100 if (ref_is_upstream_branch "$local_ref" == 0 || 101 ref_is_upstream_branch "$remote_ref" == 0) && 102 [ "$local_ref" != "$remote_ref" ]; then 103 if [ "$remote" == "origin" ]; then 104 echo >&2 "Not pushing: $local_ref to $remote_ref" 105 echo >&2 "If you really want to push this, use --no-verify." 106 exit 1 107 else 108 continue 109 fi 110 fi 111 112 # Check for fixup! commit 113 commit=$(git rev-list -n 1 --grep '^fixup!' "$range") 114 if [ -n "$commit" ]; then 115 echo >&2 "Found fixup! commit in $local_ref, not pushing" 116 echo >&2 "If you really want to push this, use --no-verify." 117 exit 1 118 fi 119 120 # Check for squash! commit 121 commit=$(git rev-list -n 1 --grep '^squash!' "$range") 122 if [ -n "$commit" ]; then 123 echo >&2 "Found squash! commit in $local_ref, not pushing" 124 echo >&2 "If you really want to push this, use --no-verify." 125 exit 1 126 fi 127 fi 128 done 129 130 exit 0