1.布景

运用Git做项目的版别操控时,在版别系统中会有许多的代码的提交记载,咱们运用git log指令就会得到如下图中的提交记载:

使用Git Hook技术定义和校验代码提交模板

当咱们的项目比较简单,规模较小、开发人员也只要一两个的时分,其实能够不必界说代码的提交记载模板,可是当咱们的项目开始变得庞大,有许多的开发者都在参加开发的时分,咱们会发现每个人提交的信息都是千奇百怪的,呈现了一个问题,要定位具体的提交时更是如大海捞针。特别痛苦。所以Git提供了代码提交记载模板,和对提交记载模板的验证,让每个提交代码的开发者依照模板填写提交的信息,提交后再验证下开发者是否依照模板的要求填写提交信息,假如没有就不让其履行接下来的git push指令。

2.解决计划

2.1 技能可行性

2.1.1 怎么完结

其实当咱们创立了一个Git的本地库房后,项目的根目录下看到一个.git文件夹,在文件夹下的hooks目录下有许多的.sample 为后缀的文件,如下图所示

使用Git Hook技术定义和校验代码提交模板

这些文件便是咱们要改造的脚本,这个以“.sample”后缀结束的脚本文件是不会履行的,假如需求履行,咱们需求去掉“.sample” 后缀。咱们要完结的功用是界说Git提交模板和校验模板的正确性。所以咱们能够参阅prepare-commit-msg.sample(提交模板)和commit-msg.sample(验证模板)完结咱们的功用,修改完这个模板后咱们就能够运用模板了,当咱们需求运用指令git commit 提交代码时,在呈现的提交信息修改器中会呈现咱们在prepare-commit-msg脚本中界说好的模板,咱们填写完模板后保存模板,这时会运用commit-msg脚本对模板做校验。这样的话咱们的本地提交代码就能运用咱们界说好的模板了。

2.1.2 怎么同步装备到项目中其他开发者

现在还有一个问题,便是这些装备都是在咱们的本地,项目中的其他开发者并没有这个环境,咱们假如让他们去装备显然不合适,由于有的人可能不会理睬你。所以咱们需求做到让开发者无感知的就装上了咱们的环境,原理其实便是咱们将模板提交到代码库房中,然后通过脚本将装备的模板拷贝到用户的”.git/hooks”目录下,当用户触发某个操作时,就履行脚本。本文咱们以Android项目为比如,运用Gradle脚本,当用户履行构建操作的时分,咱们履行装备提交模板的脚本

2.2 完结计划

2.2.1 提交模板的脚本示例

.git/hooks目录下,复制prepare-commit-msg.sample文件,重命名为prepare-commit-msg(留意这儿没有“.sample后缀名”),咱们界说一个模板:

项目称号: [MountTai] 部分称号: [] 禅道BUGID: [无] 原因剖析: {} 解决计划: {}

prepare-commit-msg:(脚本是用perl言语和shell言语搭配写的,比较简单就不细讲了),逻辑便是在开发者进入修改器之前,往修改器写入咱们的模板。这样修改器翻开后显现的便是咱们写的模板啦。

#!/bin/sh
COMMIT_MSG_FILE=$1
COMMIT_SOURCE=$2
SHA1=$3
case "$2,$3" in
 merge,)
  /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;
 ,|template,)
  /usr/bin/perl -i.bak -pe 'print "项目称号: [MountTai] 部分称号: [] 禅道BUGID: [无]\n
  #部分称号: Android开发部 / 三维软件部 \n\n原因剖析: {}\n解决计划: {}\n" if /^#/ && $first++ == 0' "$1" ;;
 *) ;;
esac

这个文件编写好后,直接放到.git/hooks目录下,然后咱们履行git commit 指令后就会呈现下图中的模板

使用Git Hook技术定义和校验代码提交模板

提交修改界面:这儿需求重点留意下,如上图所示,在修改器的最上面会有一个空格,这个空格需求咱们手动删去,然后再填写咱们的提交信息。若是无法修改,请将输入法切换为英文,按下键盘的i键,进入修改形式,要保存的时分,切换输入法到英文,然后按下esc键,能够按下 shift+zz 组合键直接保存,或者按下shift + : 进入指令形式,再输入wq,回车就行了,抛弃则输入q!

删去空格后,榜首行会显现黄色,如下图:

使用Git Hook技术定义和校验代码提交模板

2.2.2 校验模板示例

复制.git/hooks下的commit-msg.sample文件,重命名为commit-msg,然后编写模板校验规则,运用正则表达式验证开发者提交的代码信息。下面的逻辑便是获取提交的信息后,运用正则表达式去匹配。成功的话就能够持续提交,否则的话提示用户消息提交格局不合法,重新修改提交

commit_msg=`cat $1`
msg_re="^(项目称号|部分称号|禅道BUGID|原因剖析|解决计划)(\(.+\))?: .{1,100}"
if [[ ! $commit_msg =~ $msg_re ]]
then
   echo -e "不合法的 commit 消息提交格局,请运用正确的格局:\n
   详情请查看 git commit 提交标准:https://t3hx1u77li.feishu.cn/docx/CJr7d7aHJofPcYxOA1NcISVBn0d"
   # 异常退出
   exit 1 
fi

提交成功会展示:

使用Git Hook技术定义和校验代码提交模板

失败会显现

使用Git Hook技术定义和校验代码提交模板

标出的部分,便是提交标准文档,让开发者能够在失败的时分通过这个文档查看提交标准。

2.2.3 装备同步到项目的其他开发者脚本示例

(1)本地装备好了后,咱们就能够把prepare-commit-msg和commit-msg两个脚本放到你的项目根目录下

使用Git Hook技术定义和校验代码提交模板

(2)创立一个gradle脚本,做环境拷贝作业

使用Git Hook技术定义和校验代码提交模板

Git装备提交模板和校验模板的gradle脚本示例:

def useGitTemplate = false
project.afterEvaluate {
    if(useGitTemplate){
        preBuild.dependsOn('resetGitHookConfig')
    } else {
        println("exec tasks")
        preBuild.dependsOn('prepareCommitMsgConfig')
    }
}
task prepareCommitMsgConfig(type:Copy){
    from(getCommitMsgConfigFile().toString())
    into(getGitHookDir().toString())
    File file = new File(getGitHookDir())
    println("GitHookDir: " + getGitHookDir() + " ,permission: " + file.exists() +
            " ,readable: " + file.canRead() + " ,writable: " + file.canWrite())
    into(getGitHookDir().toString())
    from(getPrePareCommitMsgConfigFile().toString())
}
task resetGitHookConfig{
    doFirst {
        File commitMsgFile = getGitHookFile('commit-msg')
        if(commitMsgFile != null){
            commitMsgFile.delete()
        }
        File prepareCommitMsgFile = getGitHookFile('prepare-commit-msg')
        if(commitMsgFile != null){
            prepareCommitMsgFile.delete()
        }
    }
}
def getGitHookFile(fileName){
    def dirPath = getGitHookDir()
    println("getGitHookFile:dirPath: " + dirPath)
    if(dirPath != null && dirPath.length() > 0){
        def file = new File(dirPath, fileName)
        println("getGitHookFile: file path: " + file.absolutePath)
        if(file.exists()){
            return file
        }
    }
    return null
}
def getCommitMsgConfigFile(){
    File configFile = new File(project.rootDir,"git-hook/commit-msg")
    println("getCommitMsgConfigFile: configFile: " + configFile.absolutePath
    + " ,isExist: " + configFile.exists())
    if (configFile.exists()){
        return configFile.absolutePath
    }
    return null
}
def getPrePareCommitMsgConfigFile(){
    File configFile = new File(project.rootDir,"git-hook/prepare-commit-msg")
    println("getPrePareCommitMsgConfigFile: prepareConfigFile: " + configFile.absolutePath
    + " ,isExist: " + configFile.exists())
    if (configFile.exists()){
        return configFile.absolutePath
    }
    return null
}
def getGitHookDir() {
    File gitHookDir = new File(project.rootDir,".git/hooks")
    if (!gitHookDir.exists()) {
        println("Your project can't find .git directory in the ${project.rootDir.absolutePath}," +
                " please ensure it have been tracked by git VCS!")
        return null
    }
    return gitHookDir.absolutePath
}

脚本的意思便是当咱们运行Android的构建时,就会履行咱们的这个脚本,把项目中的prepare-commit-msgcommit-msg脚本拷贝到开发者的.git/hooks目录下,然后开发者就能够运用提交模板和验证功用了

提交代码的时分若是运用图形界面,能够把模板复制到界面中提交

使用Git Hook技术定义和校验代码提交模板

Git 模板改造完后,咱们的提交记载就会变得很规整了

使用Git Hook技术定义和校验代码提交模板

3.总结

Git Hook技能能够用来完结许多功用,比如在push操作之前想做一些其他操作,和Java的hook技能差不多,都是希望履行某个操作之前或者之后先履行咱们界说的操作,运用这个技能能够做代码的标准验证,提交模板的界说,模板的校验等功用,更多的功用后面用到的时分再做分享。