There are quite a few issues to work around here. The first is the one that's tripping you up: git hooks may be run from odd directories (so ../something may not be what you expect) and have $GIT_DIR set to something (typically . or .git depending on which directory they're in). Moving to another directory and running a git command doesn't work, because you wind up in the wrong place or $GIT_DIR points to the wrong place, or both.
I believe the pre-push hook is run from the directory you're thinking it's in (in most cases: it all falls apart if you use git --work-tree=<path> from somewhere entirely outside <path>), so it's just the $GIT_DIR setting that's causing the immediate problem.
Less obviously but still quite important, the current branch, which you're finding with git rev-parse, is not necessarily the branch being pushed-to, and the commit being pushed-from is not necessarily the tip of any branch. For instance:
$ git push origin zog~3:master
tells git to ask the remote to set their master to whatever commit-ID zog~3 results in, even if you're currently on branch rye. You might not care about handling this case, but it is possible to handle: a pre-push hook receives, on its standard input, a series of lines of the form:
<local ref> SP <local sha1> SP <remote ref> SP <remote sha1> LF
(this is direct from the documentation). To handle this in sh or bash:
while read lref lsha rref rsha; do ... done
where the ... part uses $lref and $lsha to work out the local reference name (if any) and SHA-1, and the remote reference name and SHA-1 (the remote name will be fully qualified, so a push to master will give you refs/heads/master in $rref).
The trickiest bit is that if you want to something with the commit that the remote will set their label to (assuming the push eventually succeeds—this is not something you can tell in the hook!), you can't rely on the current work-tree's files:
- they may be modified but not yet added and/or committed, or
- they may not be associated with the commit being pushed.
To do a really thorough job of inspecting or using them, you'd need to extract all those files to a temporary work area (which is actually pretty easy, just git --work-tree=$tmpdir checkout $lsha where $lsha is the SHA-1 you read from the input, and $tmpdir is a suitable temporary work-tree that you remove once you're done with it; but then you may also need to override $GIT_INDEX_FILE as well).
Ignoring most of that, though, the following quite cheesy (and untested) script (written in sh but should work fine with bash) may get most of the way there:
#! /bin/sh . git-sh-setup # for require_clean_work_tree() and die() check_push_to_master() { # we're pushing to remote "master"; reject if # the work tree is not clean or is not at the # commit-ID ($1) being pushed local headsha pushsha require_clean_work_tree 'push to master' headsha=$(git rev-parse HEAD) pushsha=$1 [ $headsha = $pushsha ] || die "HEAD commit $headsha does not match push to master $pushsha" } to_master=false while read lref lsha rref rsha; do case $rref in refs/heads/master) check_push_to_master $lsha; to_master=true;; esac done # if we get here it's OK to try the push, but first... if $to_master; then unset GIT_DIR # make git work normally again # set -e # might want this to make sure any failures => stop push webpack cp bundle.js ../utility cd ../utility && git add bundle.js && git commit -m "updated east_boston.js" fi exit 0 # allow push to proceed