Git Hooks简介
如同其他许多的版本控制系统一样,Git也具有在特定的操作事件发生之前或之后执行特定脚本代码功能。 Git Hooks就是那些在Git执行特定事件(如commit、push、receive等)后触发运行的脚本。 按照Git Hooks脚本所在的位置可以分为两类:
- 本地Hooks 开发者在本地进行操作,常见的触发事件有commit、merge等。
- 服务端Hooks 开发者提交代码之后,由服务端操作,常见的触发事件有receive等。
Git Hooks使用场景简介
Git Hooks是定制化的脚本程序,所以它实现的功能与相应的git动作相关。 在实际工作中,Git Hooks还是相对比较万能的。以下仅举几个简单的例子:
- pre-commit: 检查每次的提交的message是否有拼写错误,或是否符合某种指定的命名规范。
- pre-receive: 统一上传到远程库的代码的编码,如windows默认编码为GBK,但上传时统一修改成UTF8。
- post-receive: 每当有新的提交的时候就通知项目成员(可以使用Email或SMS等方式)。
- post-receive: 开发提交代码之后把代码推送到测试环境进行验证,或者触发CI开始进入自动化流程。
- …
Git Hooks工作方式
每一个Git代码仓库下都包含有.git/hoooks这个目录,此处为放置Hooks的地方。当指定操作被执行时,git将会调用该目录下的某个名称脚本。 以下为常见的:
applypatch-msg
pre-applypatch
post-applypatch
pre-commit
prepare-commit-msg
commit-msg
post-commit
pre-rebase
post-checkout
post-merge
pre-receive
update
post-receive
post-update
pre-auto-gc
post-rewrite

上图为一个本机某个仓库下的hooks目录列表。具体在使用时需要将该目录中的xxxx.sample文件中的.sample去掉,git默认已经绑定常用事件与hooks的文件名。
Git Hooks具体操作流程
从上图可见,hooks目录下的均是可执行文件。尽管默认这些文件默认是shell脚本,但你完全可以给它替换成自己喜欢的Ruby,Python或者Perl。
通常,只需要将该文件的第一行改成具体需要执行的程序名称。
如使用python时,将首行中的#!/bin/sh改成#!/usr/bin/env python,脚本中的内容即可以为python语法的脚本内容了(当然如果是python的话别忘了编码方式)。
关于这些脚本文件的命名,很容易发现图中的文件都是上面【Git Hooks工作方式】列表中列出的名称加上后缀.sample。 正式使用时,将仓库hooks目录下的文件后缀名去掉,或者以列表中的名字直接命名,就会把该脚本绑定到特定的Git行为上。 因为git行为操作名已经固定,故Git Hooks的正确操作方式其实就是简单的写脚本!!!
Git Hooks脚本分类
Git Hooks脚本可以按照运行环境分为两类:本地Hooks与服务端Hooks。
本地Hooks
也称客户端Hooks、客户侧Hooks。 占常用hooks的大多数,按照功能可以给它们分成三类:通知类、提交类、其他。
-
通知类Hooks
与git am相关的脚本。均由git am触发运行,按顺序依次是:
applypatch-msg,pre-applypatch,post-applypatch。
如果在工作流中用不到这个命令,那也就无所谓了。不过,如果要用git format-patch命令通过Email提交补丁,这部分内容还是比较有用的。-
applypatch-msg
脚本最先被触发,它包含一个参数,用来规定提交说明文件的路径。该脚本可以修改文件中保存的提交说明,以便规范提交说明以符合项目标准。
如果提交说明不符合规定的标准,脚本返回非零值,git终止提交。 说明一点,这个脚本看上去和commit-msg作用几乎一样。也就是说,该脚本会调用commit-msg并执行。实际上,这一切都是可修改的。 -
pre-applypatch
会在补丁应用后但尚未提交前运行。这个脚本没有参数,可以用于对应用补丁后的工作区进行测试,或对git tree进行检查。如果不能通过测试或检查,脚本返回非零值,git终止提交。 同样需要注意,git提供的此默认脚本中只是简单调用了pre-commit,因此在实际工作中需要视情况修改。 -
post-applypatch
脚本会在补丁应用并提交之后运行,它不包含参数,也不会影响git am的运行结果。该脚本可以用来向工作组成员或补丁作者发送通知。
-
-
提交类Hooks
与git commit相关的hooks一共有四个,均由git commit命令触发调用,按照一次发生的顺序分别是:pre-commit、prepare-commit-msg、commit-msg、post-commit。-
pre-commit
本脚本是最先触发运行的脚本。在提交一个commit之前,该hook有能力做许多工作,比如检查待提交东西的快照,以确保这份提交中没有缺少什么东西、文件名是否符合规范、是否对这份提交进行了测试、代码风格是否符合团队要求等等。 这个脚本可以通过传递–no-verify参数而禁用,如果脚本运行失败(返回非零值),git提交就会被终止。 -
prepare-commit-msg
脚本会在默认的提交信息准备完成后但编辑器尚未启动之前运行。 这个脚本的作用是用来编辑commit的默认提交说明。 该脚本有1~3个参数:包含提交说明文件的路径,commit类型(message, template, merge, squash),一个用于commit的SHA1值。 这个脚本用的机会不是太多,主要是用于能自动生成commit message的情况。 不会因为–no-verify参数而禁用,如果脚本运行失败(返回非零值),git提交就会被终止。 -
commit-msg
包含有一个参数,用来规定提交说明文件的路径。 该脚本可以用来验证提交说明的规范性,如果作者写的提交说明不符合指定路径文件中的规范,提交就会被终止。 该脚本可以通过传递–no-verify参数而禁用,如果脚本运行失败(返回非零值),git提交就会被终止。 -
post-commit
脚本发生在整个提交过程完成之后。这个脚本不包含任何参数,也不会影响commit的运行结果,可以用于发送new commit通知。
需要注意到,这几个脚本并不会通过clone传到项目中,而且既然是完全运行在本地,那就无法完全保证验证能起到作用(可以随便修改),但为了保证一些项目的可靠性,还需要开发者们自觉遵守这些规则。
-
-
其他Hooks
-
pre-rebase
由git rebase命令调用,运行在rebase执行之前,可以用来阻止任何已发发生过的提交参与基础库的变更(有些文档也叫变基)。 默认的pre-rebase确实是这么做的,不过脚本中的next是根据Git项目自身而写的分支名,在使用过程中应该将其改成自己的稳定分支名称。 -
post-checkout
由git checkout命令调用,在完成工作区更新之后执行。该脚本由三个参数:之前HEAD指向的引用,新的HEAD指向的引用,一个用于标识此次检出是否是分支检出的值(0表示文件检出,1表示分支检出)。 也可以被git clone触发调用,除非在克隆时使用参数–no-checkout。在由clone调用执行时,三个参数分别为null, 1, 1。 这个脚本可以用于为自己的项目设置合适的工作区,比如自动生成文档、移动一些大型二进制文件等,也可以用于检查版本库的有效性。 -
post-merge
由git merge调用,在merge成功后执行。该脚本有一个参数,标识合并是否为压缩合并。该脚本可以用于对一些Git无法记录的数据的恢复,比如文件权限、属主、ACL等。
-
服务端Hooks
除了本地执行的Hooks脚本之外,还有一些放在Git Server上的Hooks脚本,作为管理员,可以利用这些服务端的脚本来强制确保项目的任何规范。
这些运行在服务端的脚本,会在push命令发生的前后执行。
pre系列的脚本可以在任何时候返回非零值来终止某次push,并向push方返回一个错误。