背景
我们正在使用nagios监视我们的基础设施。 目前我们没有版本控制下的nagiosconfiguration,而且我们有两个pipe理nagiosconfiguration。 因此,我正在努力将我们的nagiosconfiguration变成一个中心的git仓库,使用一些钩子来做语法检查,然后如果configuration看起来不错,就让它们“活跃”。 我使用这个人的职位作为一个起点。
我试图实现的一般工作stream程是:
git push origin master
到远程回购。 git pull
新代码拖到活动的nagiosconfiguration目录中,然后重新启动nagios。 我遇到了一个奇怪的行为,但是,当我拒绝由于在nagiosconfiguration语法错误的git推。 我期望发生的事情是,如果我拒绝这个钩子,那么尝试的推送应该离开存储库,原封不动。 但似乎并非如此。 以下是我所看到的细节:
问题
我在本地编辑nagiosconfiguration,故意包含语法错误,添加,然后在本地提交:
host:nagios erik$ vi nagios.cfg host:nagios erik$ git add nagios.cfg host:nagios erik$ git commit -m "syntax error" [master da71aed] syntax error 1 files changed, 1 insertions(+), 0 deletions(-)
现在我把这些改变推到主回购。 由于语法错误,这将被拒绝:
host:nagios erik$ git push origin master Counting objects: 5, done. Delta compression using up to 8 threads. Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 12.74 KiB, done. Total 3 (delta 1), reused 2 (delta 1) remote: Previous HEAD position was 3ddc880... removed syntax error remote: HEAD is now at da71aed... syntax error remote: Nagios Config Check Exit Status: 254 remote: Your configs did not parse correctly, there was an error. Output follows. remote: remote: Nagios Core 3.2.3 remote: Copyright (c) 2009-2010 Nagios Core Development Team and Community Contributors remote: Copyright (c) 1999-2009 Ethan Galstad remote: Last Modified: 10-03-2010 remote: License: GPL remote: remote: Website: http://www.nagios.org remote: Reading configuration data... remote: Error in configuration file '/tmp/nagiosworkdir/nagios.cfg' - Line 23 (NULL value) remote: Error processing main config file! remote: remote: remote: remote: ***> One or more problems was encountered while processing the config files... remote: remote: Check your configuration file(s) to ensure that they contain valid remote: directives and data defintions. If you are upgrading from a previous remote: version of Nagios, you should be aware that some variables/definitions remote: may have been removed or modified in this version. Make sure to read remote: the HTML documentation regarding the config files, as well as the remote: 'Whats New' section to find out what has changed. remote: To [email protected]:nagios ! [remote rejected] master -> master (pre-receive hook declined) error: failed to push some refs to '[email protected]:nagios'
这不应该触及远程回购,但它确实。 如果我切换到另一个本地临时目录,并尝试克隆回购,我得到:
host:temp erik$ git clone [email protected]:nagios Cloning into nagios... remote: Counting objects: 30, done. remote: Compressing objects: 100% (29/29), done. remote: Total 30 (delta 12), reused 0 (delta 0) Receiving objects: 100% (30/30), 29.81 KiB, done. Resolving deltas: 100% (12/12), done. error: Trying to write ref HEAD with nonexistant object da71aedfde2e0469288acd9e45bb8b57a6e5a7b3 fatal: Cannot update the ref 'HEAD'.
现在我回到原来的工作目录,修复语法错误,添加,提交和推送:
host:nagios erik$ vi nagios.cfg host:nagios erik$ git add nagios.cfg host:nagios erik$ git commit -m "removing syntax error, push should succeed this time" [master f147ded] removing syntax error, push should succeed this time 1 files changed, 0 insertions(+), 2 deletions(-) host:nagios erik$ git push origin master Counting objects: 6, done. Delta compression using up to 8 threads. Compressing objects: 100% (4/4), done. Writing objects: 100% (4/4), 487 bytes, done. Total 4 (delta 2), reused 0 (delta 0) remote: Previous HEAD position was 4c80d45... syntax error remote: HEAD is now at f147ded... removing syntax error, push should succeed this time remote: Nagios Config Check Exit Status: 0 remote: Your configs look good and parsed correctly. To [email protected]:nagios 3ddc880..f147ded master -> master
在这一点上,存储库是好的,我可以改变到一个临时目录并再次克隆回购:
host:temp erik$ git clone [email protected]:nagios Cloning into nagios... remote: Counting objects: 34, done. remote: Compressing objects: 100% (33/33), done. remote: Total 34 (delta 14), reused 0 (delta 0) Receiving objects: 100% (34/34), 30.22 KiB, done. Resolving deltas: 100% (14/14), done.
这是我正在使用的预接收钩子。
我在客户端上使用git v1.7.5.4,在服务器上使用v1.7.2.3。
所以,对于这个问题 :当我拒绝推送时,为什么存储库处于不一致的状态? 有什么东西与我的混帐钩或我的理解git缺乏?
你在做:
export GIT_WORK_TREE=/tmp/nagiosworkdir /usr/bin/git checkout -f $NEW_SHA1
在你的钩子。 虽然它没有触及你通常的工作拷贝,但它正在更新git-dir中的引用(特别是HEAD
引用),如你的错误所示:
... remote: HEAD is now at da71aed... syntax error ...
您的挂钩正在执行exit 1
拒绝更新,但它没有(重新)失败后重置HEAD
引用。
我认为你需要更新你的钩子中的失败分支,如下所示:
... if [ "$NAGIOS_CHECK_STATUS" -ne 0 ] then echo "Your configs did not parse correctly, there was an error. Output follows." cat $GIT_WORK_TREE/check.out /usr/bin/git reset --hard $OLD_SHA1 # <-- Add This exit 1 else ...
钩子中的git checkout
命令创build/更新仓库中的HEAD引用。
如果你的仓库是一个裸仓库,它可以没有HEAD参考(新的克隆将默认检出它的主分支,如果有的话); 在退出之前只需要删除HEAD文件(也许在一个trap
这样你就不必在每个exit
之前单独安排)。 在脚本的任何地方“早”:
trap 'git update-ref -m "removing HEAD after temporary checkout to alternate workdir" -d HEAD "$NEW_SHA1"' 0
如果你的版本库不是裸露的,或者你想维护一个HEAD ref(这样克隆默认会检出一些其他的分支),那么你必须保存HEAD ref并在退出之前恢复它。
首先,在服务器的仓库中,将HEAD ref重置为指向您希望在新克隆中默认检出的分支:
git symbolic-ref -m 'setting default branch for new clones' HEAD refs/heads/master
然后,在你的钩子脚本(在结账之前的任何地方):
# Restore HEAD symref when exiting saved_HEAD=$(git symbolic-ref HEAD) trap 'git symbolic-ref -m "restoring HEAD after temporary checkout to alternate workdir" HEAD "$saved_HEAD"' 0
顺便提一下, pre-receive
钩子应该确保它们完全读取标准input,并处理所有input的行。 在消耗所有input之前退出有时会在git-receive-pack
过程中触发一个SIGPIPE; 这可能不会出现在你的情况下,如果你只是一次推一个裁判(因为你至less读过一行),但是要记住。 也许更容易做这个钩子作为一个update
挂钩,你只需要一次关注一个裁判,并可以拒绝每个裁判推个别(也许你只关心保持主干尖“干净”;而你检查并报告其他分支机构的提示,但从不拒绝,以便在不完整的工作中用于协作)。