8.3 Customizing Git - Git Hooks 钩子 自动拉取 自动部署 提交工作流钩子,电子邮件工作流钩子和其他钩子
https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks
https://github.com/git/git/blob/master/templates/hooks--commit-msg.sample
8.3 Customizing Git - Git Hooks
Git Hooks
Like many other Version Control Systems, Git has a way to fire off custom scripts when certain important actions occur. There are two groups of these hooks: client-side and server-side. Client-side hooks are triggered by operations such as committing and merging, while server-side hooks run on network operations such as receiving pushed commits. You can use these hooks for all sorts of reasons.
Installing a Hook
The hooks are all stored in the hooks
subdirectory of the Git directory. In most projects, that’s .git/hooks
. When you initialize a new repository with git init
, Git populates the hooks directory with a bunch of example scripts, many of which are useful by themselves; but they also document the input values of each script. All the examples are written as shell scripts, with some Perl thrown in, but any properly named executable scripts will work fine – you can write them in Ruby or Python or whatever language you are familiar with. If you want to use the bundled hook scripts, you’ll have to rename them; their file names all end with .sample
.
To enable a hook script, put a file in the hooks
subdirectory of your .git directory that is named appropriately (without any extension) and is executable. From that point forward, it should be called. We’ll cover most of the major hook filenames here.
Client-Side Hooks
There are a lot of client-side hooks. This section splits them into committing-workflow hooks, email-workflow scripts, and everything else.
Note
|
It’s important to note that client-side hooks are not copied when you clone a repository. If your intent with these scripts is to enforce a policy, you’ll probably want to do that on the server side; see the example in An Example Git-Enforced Policy. |
Committing-Workflow Hooks
The first four hooks have to do with the committing process.
The pre-commit
hook is run first, before you even type in a commit message. It’s used to inspect the snapshot that’s about to be committed, to see if you’ve forgotten something, to make sure tests run, or to examine whatever you need to inspect in the code. Exiting non-zero from this hook aborts the commit, although you can bypass it with git commit --no-verify
. You can do things like check for code style (run lint
or something equivalent), check for trailing whitespace (the default hook does exactly this), or check for appropriate documentation on new methods.
The prepare-commit-msg
hook is run before the commit message editor is fired up but after the default message is created. It lets you edit the default message before the commit author sees it. This hook takes a few parameters: the path to the file that holds the commit message so far, the type of commit, and the commit SHA-1 if this is an amended commit. This hook generally isn’t useful for normal commits; rather, it’s good for commits where the default message is auto-generated, such as templated commit messages, merge commits, squashed commits, and amended commits. You may use it in conjunction with a commit template to programmatically insert information.
The commit-msg
hook takes one parameter, which again is the path to a temporary file that contains the commit message written by the developer. If this script exits non-zero, Git aborts the commit process, so you can use it to validate your project state or commit message before allowing a commit to go through. In the last section of this chapter, we’ll demonstrate using this hook to check that your commit message is conformant to a required pattern.
After the entire commit process is completed, the post-commit
hook runs. It doesn’t take any parameters, but you can easily get the last commit by running git log -1 HEAD
. Generally, this script is used for notification or something similar.
Email Workflow Hooks
You can set up three client-side hooks for an email-based workflow. They’re all invoked by the git am
command, so if you aren’t using that command in your workflow, you can safely skip to the next section. If you’re taking patches over email prepared by git format-patch
, then some of these may be helpful to you.
The first hook that is run is applypatch-msg
. It takes a single argument: the name of the temporary file that contains the proposed commit message. Git aborts the patch if this script exits non-zero. You can use this to make sure a commit message is properly formatted, or to normalize the message by having the script edit it in place.
The next hook to run when applying patches via git am
is pre-applypatch
. Somewhat confusingly, it is run after the patch is applied but before a commit is made, so you can use it to inspect the snapshot before making the commit. You can run tests or otherwise inspect the working tree with this script. If something is missing or the tests don’t pass, exiting non-zero aborts the git am
script without committing the patch.
The last hook to run during a git am
operation is post-applypatch
, which runs after the commit is made. You can use it to notify a group or the author of the patch you pulled in that you’ve done so. You can’t stop the patching process with this script.
Other Client Hooks
The pre-rebase
hook runs before you rebase anything and can halt the process by exiting non-zero. You can use this hook to disallow rebasing any commits that have already been pushed. The example pre-rebase
hook that Git installs does this, although it makes some assumptions that may not match with your workflow.
The post-rewrite
hook is run by commands that replace commits, such as git commit --amend
and git rebase
(though not by git filter-branch
). Its single argument is which command triggered the rewrite, and it receives a list of rewrites on stdin
. This hook has many of the same uses as the post-checkout
and post-merge
hooks.
After you run a successful git checkout
, the post-checkout
hook runs; you can use it to set up your working directory properly for your project environment. This may mean moving in large binary files that you don’t want source controlled, auto-generating documentation, or something along those lines.
The post-merge
hook runs after a successful merge
command. You can use it to restore data in the working tree that Git can’t track, such as permissions data. This hook can likewise validate the presence of files external to Git control that you may want copied in when the working tree changes.
The pre-push
hook runs during git push
, after the remote refs have been updated but before any objects have been transferred. It receives the name and location of the remote as parameters, and a list of to-be-updated refs through stdin
. You can use it to validate a set of ref updates before a push occurs (a non-zero exit code will abort the push).
Git occasionally does garbage collection as part of its normal operation, by invoking git gc --auto
. The pre-auto-gc
hook is invoked just before the garbage collection takes place, and can be used to notify you that this is happening, or to abort the collection if now isn’t a good time.
Server-Side Hooks
In addition to the client-side hooks, you can use a couple of important server-side hooks as a system administrator to enforce nearly any kind of policy for your project. These scripts run before and after pushes to the server. The pre hooks can exit non-zero at any time to reject the push as well as print an error message back to the client; you can set up a push policy that’s as complex as you wish.
pre-receive
The first script to run when handling a push from a client is pre-receive
. It takes a list of references that are being pushed from stdin; if it exits non-zero, none of them are accepted. You can use this hook to do things like make sure none of the updated references are non-fast-forwards, or to do access control for all the refs and files they’re modifying with the push.
update
The update
script is very similar to the pre-receive
script, except that it’s run once for each branch the pusher is trying to update. If the pusher is trying to push to multiple branches, pre-receive
runs only once, whereas update runs once per branch they’re pushing to. Instead of reading from stdin, this script takes three arguments: the name of the reference (branch), the SHA-1 that reference pointed to before the push, and the SHA-1 the user is trying to push. If the update script exits non-zero, only that reference is rejected; other references can still be updated.
post-receive
The post-receive
hook runs after the entire process is completed and can be used to update other services or notify users. It takes the same stdin data as the pre-receive
hook. Examples include emailing a list, notifying a continuous integration server, or updating a ticket-tracking system – you can even parse the commit messages to see if any tickets need to be opened, modified, or closed. This script can’t stop the push process, but the client doesn’t disconnect until it has completed, so be careful if you try to do anything that may take a long time.
背景描述
在刚开始用git的时候,每次都是将本地将代码push到远程仓库,然后再ssh到服务器上git pull,甚是麻烦。后来在项目开发中使用git的时候,发现push之后,编译系统竟然会有自动部署等功能。顿时觉得这等神器,必须学习一下,所以就请教了吴旭东老师。下面就是我通过Git Hook神器将自己的项目自动化部署到服务器的过程。
自动部署理论
首先要明确现在代码的分布情况,开发者电脑上的本地仓库,git服务器上的远端仓库,web服务器上的另一个本地仓库,我们浏览器访问的就是这里的代码。其实自动部署就是要当从开发者本地仓库提交代码到远端仓库的时候,自动把代码部署到web服务器的本地仓库,实现开发者本地仓库和web服务器的本地仓库的同步。(即通过GitHook中的post-receive脚本文件)
安装过程
在服务器上创建一个裸仓库(git服务器上的远端仓库)
首先要在服务器上建立一个裸仓库,我存放裸仓库的文件夹是/home/workspace/gitbook,进入到该文件夹,然后使用git init –bare springSummary.git创建裸仓库。
在服务器上创建一个普通Git仓库
在服务器上建立一个普通Git仓库用于存放网站的源代码。(web服务器上的另一个本地仓库)
mkdir /var/www/workspace
cd /var/www/workspace
git clone /home/workspace/gitbook/springSummary.git
配置Git Hook
进入到/home/workspace/gitbook/springSummary.git/hooks文件夹,使用vi post-receive创建一个脚本,当你在本地仓库执行git push后就会触发post-receive。
post-receive的内容如下:
#!/bin/sh
#判断是不是远端仓库
IS_BARE=$(git rev-parse --is-bare-repository)
if [ -z "$IS_BARE" ]; then
echo >&2 "fatal: post-receive: IS_NOT_BARE"
exit 1
fi
unset GIT_DIR
DeployPath="/var/www/workspace/springSummary"
echo "==============================================="
cd $DeployPath
echo "deploying the test web"
#git stash
#git pull origin master
git fetch --all
git reset --hard origin/master
gitbook build
sleep 15
time=`date`
echo "web server pull at webserver at time: $time."
echo "================================================"
保存后赋予可执行权限:
chmod +x /var/www/workspace/springSummary/hooks/post-receive
1
这样在开发者提交代码的时候,就会自动部署。
在这里需要解释两个问题:
在这里第一个问题,因为我部署的是一个gitbook项目,所以需要额外在脚本中添加一行指令gitbook build,但是仅添加这一行的话会导致最后这个脚步执行失败,因为build需要大约8秒时间。所以我的解决方案是在脚本中添加sleep 15,这样可以等待build执行结束并把结果返回到显示的终端。(如果只是需要自动更新项目,请把这两行指令删去)
在这里我使用的是git fetch,为什么没有用git pull实现。区别在于:
git fetch:相当于是从远程获取最新版本到本地,不会自动merge。
git pull:相当于是从远程获取最新版本并merge到本地。
pull实现相当于fetch后再用merge,来合并本地和远端的代码。
这里就有个问题,如果开发者在提交过程出现失误,使用git reset复位后,现在远端的代码版本低于web端的代码版本,再使用pull的时候就不能实现和开发者本地的代码的同步。所以这里使用fetch后,在强制使用reset实现web端的代码版本指针和git服务端的一致。(如果在本机可以使用stash,然后pull,然后drop刚才stash的内容)
一、利用crontab定时任务
编辑用户的定时任务:
crontab -e
在用户定时任务文件里写入定时命令
每过1分钟执行后面的命令 : */1 * * * * cd /home/wwwroot/default/GIT/autoload;/usr/local/bin/git pull
cd /home/wwwroot/default/GIT/autoload 表示进入到git项目目录
/usr/local/bin/git pull 进入项目目录后拉取代码
使用post-receive钩子文件实现服务器本地仓库git项目自动化部署_WKissa的博客-CSDN博客 https://blog.csdn.net/WKissa/article/details/80417444
首先找到服务器端的git仓库里面(服务器里面的用来接收提交的代码的仓库)
然后cd进去.git的隐藏文件里面,然后打开hooks的文件
在里面vim一个post-receive文件然后在里面添加如下几行代码
DIR=/xxx/xxx
git --work-tree=${DIR} clean -fd
# 直接强制检出
git --work-tree=${DIR} checkout --force
然后给他最大权限 chmod -R 777 ./post-receive (不要问我为什么,任性,当然,755权限就够了也许) 之后进入到你服务器的
xxx/xxx文件里面新建一个git纯净库
git init --bare ygc.git
然后去本地,clone下来你该仓库的代码,之后添加一个test.txt文件,然后提交
git add .
git commit -m"test"
git push
然后你在回到之前目录ls -a 就会发现服务器已经自动化部署好了你所传的测试代码
# 客户端hooks文件夹下
hooks/
|-- applypatch-msg.sample
|-- commit-msg.sample
|-- post-update.sample
|-- pre-applypatch.sample
|-- pre-commit.sample
|-- pre-push.sample
|-- pre-rebase.sample
|-- prepare-commit-msg.sample
|-- update.sample
#服务端hooks文件夹下
hooks/
|-- applypatch-msg.sample
|-- commit-msg.sample
|-- post-update.sample
|-- pre-applypatch.sample
|-- pre-commit.sample
|-- pre-push.sample
|-- pre-rebase.sample
|-- prepare-commit-msg.sample
|-- update.sample
客户端钩子
客户端钩子有多种,可以分为:提交工作流钩子,电子邮件工作流钩子和其他钩子
pre-commit
钩子在键入提交信息前运行。可以用于检查代码风格是否一致。
prepare-commit-msg
钩子在启动提交信息编辑器之前,默认信息创建之后运行。
post-commit
钩子在整个提交过程完成后运行。常用于通知的事情。
服务端钩子
服务端钩子可以对项目执行各种类型策略。可以再推送到服务器之前运行也可以推送到服务器后在运行。
pre-receive
处理来自客户端的推送时触发
post-receive
在客户端push完成后运行,可以用来更新其它系统服务或者通知消息;本文通过这post-receive进行代码自动部署