如何Hook Git命令

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何Hook Git命令相关的知识,希望对你有一定的参考价值。

参考技术A 在项目的git仓库中有个hooks文件夹,里面默认放了12个sample文件,这些文件就是hook脚本文件,默认情况下他们都是禁用状态。要启用一个hook(钩子),需要移除其 .sample 后缀。

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

附:

原文地址

Git Hook开发实践总结

前言: Git是由Linus大牛在一周时间内开发出来的分布式版本管理系统,Linux的内核以及各类大小项目都是使用git来管理其版本以及迭代开发。本文将简要介绍其hook的功能,并通过一个特定的hook实现来展示如何来开发hook。

1 Git Hook

git在提供了一些列版本功能的功能之外,还提供了若干的扩展机制,由开发团队在其扩展点上根据需要进行定制化功能;例如,提供更为严格的提交规则检查、comment信息的检查等等。这些扩展点被成为Hook,钩子。
Git 通过Hook的方式,在特定的重要动作发生时触发自定义脚本。钩子分类:客户端的和服务器端。 客户端钩子由诸如提交和合并这样的操作所调用,而服务器端钩子作用于诸如接收被推送的提交这样的联网操作。
客户端的钩子,位于git项目的.git/hooks目录之下:

其中sample结尾的文件是由git提供的hook示例,需要的时候,只需将.sample的后缀移除,即可作为hook来使用。客户端的hook示例如下:

  • pre-commit 钩子在键入提交信息前运行。
  • prepare-commit-msg 钩子在启动提交信息编辑器之前,默认信息被创建之后运行
  • commit-msg 钩子接收一个参数,此参数即上文提到的,存有当前提交信息的临时文件的路径
  • post-commit 钩子在整个提交过程完成后运行
    其余的hook,大家可以自行检索其应用场景,使用方式大同小异。
    服务端的Hook的扩展点,具体如下:
  • pre-commit: 检查每次的commit message是否有拼写错误,或是否符合某种规范。
  • pre-receive: 统一上传到远程库的代码的编码。
  • post-receive: 每当有新的提交的时候就通知项目成员(可以使用Email或SMS等方式)。
  • post-receive: 把代码推送到生产环境。
    更多的扩展信息,可以参考git的相关文档。
    在实际项目中,大家可以根据具体情况,选择在客户端/服务端部署hook

2 自定义Hook的功能需求目标

需求描述:

写一个客户端钩子,使得任何一个在master分支上的提交都必须包含JIAR的关键字,否则提交不予允许,并给出错误提示信息。如果提交发生在非master分支上,则允许提交进行(不管是否包含JIRA关键字)

Hook分析:
客户端Hook,在commit-msg中检查是否含有JIRA关键词,并检查Branch是否为Master。

3 Hook的实现类库选择

在本示例中,选用git-python作为进行git操作的扩展类库使用,其安装指令如下:

pip install git-python

当前环境使用的Python版本为:3.7.0

4 Hook的实现步骤

  1. 新增文件 commit-msg
    文件路径: .git/hook
    内容如下:
      #!/bin/sh
      python .git/hooks/commit-msg.py $1
    
  2. 新增文件 commit-msg.py
    文件所在的路径: .git/hooks
import git
import sys, re

repo = git.Repo(search_parent_directories=True)
branch = repo.active_branch

print("currnet branch name:" + branch.name)
print("Start to commit the change in git")

#Required parts
requiredRegex = "JIRA"
requiredLength = 15

#Get the commit file
commitMessageFile = open(sys.argv[1]) #The first argument is the file
commitMessage = commitMessageFile.read().strip()

if branch.name == "master":
    print("Ready to commit the change in master")
    sys.exit(0)

if len(commitMessage) < requiredLength:
    print("Commit message is less than the required 15 characters.")
    sys.exit(1)

if re.search(requiredRegex, commitMessage) is None:
    print("A JIRA Keyword must be filled with a commit")
    sys.exit(1)
    
print("Commit message is validated")
sys.exit(0)

说明:

  1. active_branch指在当前git repository的活跃分支
  2. sys.argv[1]: 从commit-msg命令中传入的用户提交的commit注释信息
  3. sys.exit(0), 0: 表示当前流程正常结束,继续向下流转; 1: 中断当前流程

5 Hook执行效果

在master branch进行提交:

即使在commit信息中未包含JIRA,仍然可以正常提交。

在Dev branch中进行提交:

从其中可以看出,commit信息中未包含JIRA的情况下,提交失败。

6 异常问题的处理

  1. 无法执行的问题
    提示信息:
  week2 git:(dev) >> git commit -m "test it for hook"
提示:因为没有将钩子 '.git/hooks/commit-msg' 设置为可执行,钩子被忽略。您可以通过
提示:配置 `git config advice.ignoredHook false` 来关闭这条警告。
[dev 32f4480] test it for hook

现象分析: commit-msg自定义的钩子在执行中权限不足,无法被执行。
解决方法:
> chmod +x commit-msg
增加文件的执行权限。

  1. 提示文件不存在的问题
    现象以及问题:
week2 git:(dev) >> git commit -m "test it for hook again"
(null): can't open file 'commit-msg.py': [Errno 2] No such file or directory

现象分析:
无法找到文件,是由于其设置的路径不正确
解决办法:
在commit-msg中将执行python文件的路径设置一下:

#!/bin/sh  
python .git/hooks/commit-msg.py $1

路径的起点是当前git repository所在的位置。

参考文档

  1. Git Hook Reference
  2. Git Hook Example

以上是关于如何Hook Git命令的主要内容,如果未能解决你的问题,请参考以下文章

在 git hook 中操作 repo 时 -C 和 --git-dir 之间的区别

拾遗:Git 与 Svn hook 不执行问题

从post-commit git-hook运行grunt

CentOS7——gitlab本地git仓库搭建 以及web hook配置

使用 Git 跟踪 mysql 架构 - 一些问题

Git Hook开发实践总结