Git Hooks的使用

Git Hooks的使用

  • 1.git默认提供
  • 2.自定义hook操作
    • (1)直接修改
    • (2)链接自定义文件

有时我们想要在git操作时候进行一些定制化操作,比如在git commit时候检查一下提交内容是否合规、git push时候检查一下资源文件大小等等,这些功能需要我们可以在git命令执行前后进行拦截,git hooks提供了这样的能力。

1.git默认提供

我们每个通过git管理的项目,在.git/hooks/文件夹中,会提供一些默认的git hooks文件,比如pre-commit.sample pre-push.sample等。
当我们执行git命令时,git会执行相应命令的相关文件,比如:

  • pre-commit在我们新增一个commit前
  • prepare-commit-msg在我们编辑一个commit的消息前调用
  • commit-msg在我们编辑完一个commit的消息后调用
  • pre-push在我们执行一次push操作前调用

由于git默认并不会提供具体的hook操作,所以这些文件都是.sample类型的文件,不会自动执行,所以我们需要自己定义操作。

2.自定义hook操作

(1)直接修改

最简单的办法,我们可以直接将默认文件的.sample后缀去掉,然后在脚本里开发即可,不过因为文件是在.git/hooks/文件夹内,不会跟随着项目被git提交,也就无法同步给其他开发者,每次更改都需要手动修改,很不友好。

(2)链接自定义文件

那如何可以让git hooks文件,像普通项目文件一样,被git操作,同步给其他人呢?因为hook文件其实就是个脚本文件,我们可以写一个脚本文件到项目被git管理的任意目录里即可,那如何执行呢?只要在.git/hooks/里的默认脚本文件中,执行我们外部的这个文件即可。

  • 自定义脚本文件:项目根目录/githooks/commit-msg-impl.py
#!/usr/bin/env python
import sys, os, re
from subprocess import check_output
# 收集参数,第一个参数是commit的信息的文件
commit_msg_filepath = sys.argv[1]
# 打开commit提交消息的文件,检测消息是否以指定格式开头的,不是则异常退出,终止这次commit消息的提交
with open(commit_msg_filepath, 'r') as f:
    content = f.read()
    if not content.startswith("xxxx"):
        print "commit-msg: ERROR! The commit message must start with xxxx"
        sys.exit(1)
  • 默认hooks文件:.git/hooks/commit-msg
#!/bin/bash
GIT_ROOT="$(git rev-parse --show-toplevel)"
FILE_NAME=$GIT_ROOT/githooks/commit-msg-impl.py
if  [ -f "$FILE_NAME" ]; then
    source $FILE_NAME
fi

这样一来,我们只需第一次修改一遍.git/hooks/里的默认文件,后续修改hook实现时候,只需要修改外部的脚本文件即可。

那么第一次需要修改.git/hooks里文件的行为,可不可以也做成自动化的呢,总不能每个人都去操作一遍吧,答案是可以的,可以写一个脚本来完成这些事情。
inithook.sh

#!/bin/sh
# 获取项目根目录
GIT_ROOT="$(git rev-parse --show-toplevel)"
# 获取.git/hooks/根目录
HOOKS_DIR="$GIT_ROOT/.git/hooks"
# 没有时创建该目录
if [ ! -d "$HOOKS_DIR" ]; then
    mkdir "$HOOKS_DIR"
fi
# 所有需要hook的git hooks文件名
hook_names=(
    pre-commit
    prepare-commit-msg
    commit-msg
    ...)
# 在.git/hooks/下生成这些执行文件
for hook_name in ${hook_names[@]}
do
    # 生成hook文件
    REAL_HOOK_FILE=$HOOKS_DIR/$hook_name
    # 将模板文件内容copy进去
    cp $GIT_ROOT/githooks/hook-tmp $REAL_HOOK_FILE
    # 替换模板文件中的hook-tmp为正确的hook文件名
    sed -i "" "s/hook-tmp/$hook_name/g" $REAL_HOOK_FILE
    # 修改hook文件权限
    chmod a+x $REAL_HOOK_FILE
done

模板文件是什么呢?就是默认文件链接到外部执行文件的代码,因为每个hook文件都差不多,只是执行文件的名字不一样,所以可以搞一个模板。
hook-tmp.sh

#!/bin/bash
GIT_ROOT="$(git rev-parse --show-toplevel)"
FILE_NAME=$GIT_ROOT/githooks/hook-tmp-impl.py
if  [ -f "$FILE_NAME" ]; then
    source $FILE_NAME
fi

这样一来,每次更新git配置时,只需要执行一遍inithook.sh就可以了~

参考资料:自定义git hook

你可能感兴趣的:(知识积累,git相关)