介绍
官方文档:
- 英文:https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks
- 中文:https://git-scm.com/book/zh/v2/自定义-Git-Git-钩子
下面只复制了pre-commit部分文档,其他详见官方文档。
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.
翻译:
Git 钩子
和其它版本控制系统一样,Git 能在特定的重要动作发生时触发自定义脚本。 有两组这样的钩子:客户端的和服务器端的。 客户端钩子由诸如提交和合并这样的操作所调用,而服务器端钩子作用于诸如接收被推送的提交这样的联网操作。 你可以随心所欲地运用这些钩子。
安装一个钩子
钩子都被存储在 Git 目录下的 hooks
子目录中。 也即绝大部分项目中的 .git/hooks
。 当你用 git init
初始化一个新版本库时,Git 默认会在这个目录中放置一些示例脚本。 这些脚本除了本身可以被调用外,它们还透露了被触发时所传入的参数。 所有的示例都是 shell 脚本,其中一些还混杂了 Perl 代码,不过,任何正确命名的可执行脚本都可以正常使用 ------ 你可以用 Ruby 或 Python,或任何你熟悉的语言编写它们。 这些示例的名字都是以 .sample
结尾,如果你想启用它们,得先移除这个后缀。
把一个正确命名(不带扩展名)且可执行的文件放入 .git
目录下的 hooks
子目录中,即可激活该钩子脚本。 这样一来,它就能被 Git 调用。接下来,我们会讲解常用的钩子脚本类型。
客户端钩子
客户端钩子分为很多种。 下面把它们分为:提交工作流钩子、电子邮件工作流钩子和其它钩子。
Note | 需要注意的是,克隆某个版本库时,它的客户端钩子 并不 随同复制。 如果需要靠这些脚本来强制维持某种策略,建议你在服务器端实现这一功能。 (请参照 使用强制策略的一个例子 中的例子。) |
---|---|
提交工作流钩子
前四个钩子涉及提交的过程。
pre-commit
钩子在键入提交信息前运行。 它用于检查即将提交的快照,例如,检查是否有所遗漏,确保测试运行,以及核查代码。 如果该钩子以非零值退出,Git 将放弃此次提交,不过你可以用 git commit --no-verify
来绕过这个环节。 你可以利用该钩子,来检查代码风格是否一致(运行类似 lint
的程序)、尾随空白字符是否存在(自带的钩子就是这么做的),或新方法的文档是否适当。
分析
结合文档说明,git init之后其实就会生成hooks示例文件,在./.git/hooks/
目录下,*.sample
就是,使用的时候我们需要把后缀.sample
去掉,它就会生效了。
shell
$ ls -alh ./.git/hooks/
total 53K
drwxr-xr-x 1 Administrator 197121 0 5月 26 23:59 ./
drwxr-xr-x 1 Administrator 197121 0 5月 27 18:52 ../
-rwxr-xr-x 1 Administrator 197121 478 5月 26 23:59 applypatch-msg.sample*
-rwxr-xr-x 1 Administrator 197121 896 5月 26 23:59 commit-msg.sample*
-rwxr-xr-x 1 Administrator 197121 4.6K 5月 26 23:59 fsmonitor-watchman.sample*
-rwxr-xr-x 1 Administrator 197121 189 5月 26 23:59 post-update.sample*
-rwxr-xr-x 1 Administrator 197121 424 5月 26 23:59 pre-applypatch.sample*
-rwxr-xr-x 1 Administrator 197121 1.7K 5月 26 23:59 pre-commit.sample*
-rwxr-xr-x 1 Administrator 197121 416 5月 26 23:59 pre-merge-commit.sample*
-rwxr-xr-x 1 Administrator 197121 1.5K 5月 26 23:59 prepare-commit-msg.sample*
-rwxr-xr-x 1 Administrator 197121 1.4K 5月 26 23:59 pre-push.sample*
-rwxr-xr-x 1 Administrator 197121 4.8K 5月 26 23:59 pre-rebase.sample*
-rwxr-xr-x 1 Administrator 197121 544 5月 26 23:59 pre-receive.sample*
-rwxr-xr-x 1 Administrator 197121 2.8K 5月 26 23:59 push-to-checkout.sample*
-rwxr-xr-x 1 Administrator 197121 3.6K 5月 26 23:59 update.sample*
具体使用
以pre-commit为例,进行测试,文档介绍了例子是在提交之前进行代码的操作,这里就简单点:将当前时间打印到某个文件。
shell
# 新建shell
echo 'date >> now_time.txt' > print_time.sh
chmod +x print_time.sh
# 去掉后缀
mv ./.git/hooks/pre-commit.sample ./.git/hooks/pre-commit
vim ./.git/hooks/pre-commit
# <<<内容
#!/bin/sh
echo "Running pre-commit hook"
sh ./print_time.sh
git add now_time.txt
# 内容>>>
git add print_time.sh
git commit -m "feat: add print_time.sh"
# 提交打印的日志
$ git commit -m "feat: update print_time.sh"
Running pre-commit hook
[main c9bf1ef] feat: update test.sh
2 files changed, 2 insertions(+)
create mode 100644 print_time.sh
create mode 100644 now_time.txt
至此,成功实现在提交之前自动执行脚本的效果。
其他类型的hooks其实就是嵌入的时机不同,当然也有一些各自的属性,可参照这个pre-commit进行实现。