这里有很多问题需要解决。第一个是让你绊倒的那个:git hooks 可能从奇怪的目录运行(所以../something 可能不是你所期望的)并且将$GIT_DIR 设置为某些东西(通常是.或.git 取决于他们所在的目录)。移动到另一个目录并运行 git 命令不起作用,因为你在错误的地方结束或$GIT_DIR 指向错误的地方,或两者兼而有之。
我相信 pre-push 挂钩是从您认为它所在的目录运行的(在大多数情况下:如果您从完全位于 <path> 之外的某个地方使用 git --work-tree=<path>,这一切都会崩溃),所以它只是 @导致直接问题的 987654328@ 设置。
不太明显但仍然很重要,您使用git rev-parse 找到的 current 分支不一定是被推送到的分支,而被推送的提交则不是必然是任何分支的尖端。例如:
$ git push origin zog~3:master
告诉 git 要求遥控器将他们的 master 设置为任何提交 ID zog~3 的结果,即使你当前在分支 rye 上。您可能不关心处理这种情况,但它是可以处理的:预推送挂钩在其标准输入上接收一系列形式的行:
<local ref> SP <local sha1> SP <remote ref> SP <remote sha1> LF
(这是直接来自文档)。在 sh 或 bash 中处理:
while read lref lsha rref rsha; do
...
done
... 部分使用 $lref 和 $lsha 计算出本地引用名称(如果有)和 SHA-1,以及远程引用名称和 SHA-1(远程名称将是完全限定的,因此推送到master 将在$rref 中为您提供refs/heads/master。
最棘手的一点是,如果您想要提交远程将设置其标签的内容(假设推送最终成功 - 这不是您可以在挂钩中说出的内容!),您不能依赖当前工作树的文件:
- 它们可能已被修改但尚未添加和/或提交,或者
- 它们可能与被推送的提交无关。
要真正彻底地检查或使用它们,您需要将所有这些文件提取到临时工作区(这实际上非常简单,只需 git --work-tree=$tmpdir checkout $lsha 其中$lsha 是您的 SHA-1从输入中读取,$tmpdir 是一个合适的临时工作树,完成后您将其删除;但您可能还需要覆盖 $GIT_INDEX_FILE。
不过,忽略其中的大部分内容,以下相当俗气(且未经测试)的脚本(用 sh 编写,但应该可以在 bash 中正常工作)可能会获得大部分内容:
#! /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