Have you ever been wanting to push your heads against the walls when you accidentally push commits to the master/develop branchs (even they are local branches)? You can however `git reset HEAD files` to unstage the commits, however, this is not a pleasant thing to do.
Luckily, the git provides many hooks and pre-push is the one that allows you to do some checks before the git actually pushes it. The pre-push is actually a bash script that runs before the `git push` command. If the script returns 1 then nothing happens. It the script returns 0, it will continue the push operation.
The pre-push is located at each reprository under .git/hooks directory, which is hidden. The following is the sample pre-push (named pre-push.sample)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | #!/bin/sh # An example hook script to verify what is about to be pushed. Called by "git # push" after it has checked the remote status, but before anything has been # pushed. If this script exits with a non-zero status nothing will be pushed. # # This hook is called with the following parameters: # # $1 -- Name of the remote to which the push is being done # $2 -- URL to which the push is being done # # If pushing without using a named remote those arguments will be equal. # # Information about the commits which are being pushed is supplied as lines to # the standard input in the form: # # <local ref> </local><local sha1> <remote ref> </remote><remote sha1> # # This sample shows how to prevent push of commits where the log message starts # with "WIP" (work in progress). remote="$1" url="$2" z40=0000000000000000000000000000000000000000 while read local_ref local_sha remote_ref remote_sha do if [ "$local_sha" = $z40 ] then # Handle delete : else if [ "$remote_sha" = $z40 ] then # New branch, examine all commits range="$local_sha" else # Update to existing branch, examine new commits range="$remote_sha..$local_sha" fi # Check for WIP commit commit=`git rev-list -n 1 --grep '^WIP' "$range"` if [ -n "$commit" ] then echo >&2 "Found WIP commit in $local_ref, not pushing" exit 1 fi fi done exit 0 |
#!/bin/sh # An example hook script to verify what is about to be pushed. Called by "git # push" after it has checked the remote status, but before anything has been # pushed. If this script exits with a non-zero status nothing will be pushed. # # This hook is called with the following parameters: # # $1 -- Name of the remote to which the push is being done # $2 -- URL to which the push is being done # # If pushing without using a named remote those arguments will be equal. # # Information about the commits which are being pushed is supplied as lines to # the standard input in the form: # # <local ref> </local><local sha1> <remote ref> </remote><remote sha1> # # This sample shows how to prevent push of commits where the log message starts # with "WIP" (work in progress). remote="$1" url="$2" z40=0000000000000000000000000000000000000000 while read local_ref local_sha remote_ref remote_sha do if [ "$local_sha" = $z40 ] then # Handle delete : else if [ "$remote_sha" = $z40 ] then # New branch, examine all commits range="$local_sha" else # Update to existing branch, examine new commits range="$remote_sha..$local_sha" fi # Check for WIP commit commit=`git rev-list -n 1 --grep '^WIP' "$range"` if [ -n "$commit" ] then echo >&2 "Found WIP commit in $local_ref, not pushing" exit 1 fi fi done exit 0
We can check if the current branch is in one of the master branches e.g. master, origin/develop, if yes, then exit with code 1. The following pre-push script has to be chmod with executable permission. All it does is to check if current branch is forbidden, if yes, return 1 otherwise indicates 0 to continue.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #!/bin/bash # run `chmod +x .git/hooks/pre-push` (We make the hook executable by using the chmod utility.) # To bypass this hook and force the push, use 'git push --no-verify' master_branches=('origin/develop' 'master' 'develop') current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,') for branch in "${master_branches[@]}" do if [ $branch = $current_branch ]; then echo "You're about to push $branch and you don't want that" exit 1 fi done exit 0 |
#!/bin/bash # run `chmod +x .git/hooks/pre-push` (We make the hook executable by using the chmod utility.) # To bypass this hook and force the push, use 'git push --no-verify' master_branches=('origin/develop' 'master' 'develop') current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,') for branch in "${master_branches[@]}" do if [ $branch = $current_branch ]; then echo "You're about to push $branch and you don't want that" exit 1 fi done exit 0
Here is how it looks like when you try to push to master:
1 2 3 4 5 | $ git branch * master $ git push origin master You're about to push master and you don't want that error: failed to push some refs to 'https://github.com/DoctorLai/ACM.git' |
$ git branch * master $ git push origin master You're about to push master and you don't want that error: failed to push some refs to 'https://github.com/DoctorLai/ACM.git'
As the pre-push has to be on each reprository, you can copy the file at your root direction, and use the following bash command to find and copy the file to all .git/hooks directory.
1 | find . -type d -name "hooks" | grep ".git/hooks" | xargs echo cp pre-push |
find . -type d -name "hooks" | grep ".git/hooks" | xargs echo cp pre-push
On windows, I guess the pre-push is still written in BASH. However, if the above not working on Windows, you might try the following Windows BATCH script – or just for education purposes.
@echo off REM pre-push.cmd REM To bypass this hook and force the push, use 'git push --no-verify' setlocal enabledelayedexpansion set branches=origin^/develop master develop for /f "tokens=2" %%i in ('git branch') do (set current=%%i) for %%j in (%branches%) do ( if /i "%%j"=="%current%" ( echo You're about to push to %%j, you don't want that exit /b 1 ) ) endlocal exit /b 0
Git has other hooks, for example: The Git Pre-Commit Hook to Avoid Pushing Only Unit Tests In NodeJs
–EOF (The Ultimate Computing & Technology Blog) —
Last Post: How to Construct Binary Search Tree from Preorder Traversal? (C++ and Java)
Next Post: The Algorithm to Find Anagram Mappings between Two Arrays