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

 更新时间:2023年11月15日 16:16:03   作者:职场007  
这篇文章主要介绍了使用Git Hook技术定义和校验代码提交模板方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

1.背景

使用Git做项目的版本控制时,在版本系统中会有很多的代码的提交记录,我们使用git log命令就会得到如下中的提交记录:

当我们的项目比较简单,规模较小、开发人员也只有一两个的时候,其实可以不用定义代码的提交记录模板,但是当我们的项目开始变得庞大,有很多的开发者都在参与开发的时候,我们会发现每个人提交的信息都是千奇百怪的,出现了一个问题,要定位具体的提交时更是如大海捞针。特别痛苦。

所以Git提供了代码提交记录模板,和对提交记录模板的验证,让每个提交代码的开发者按照模板填写提交的信息,提交后再验证下开发者是否按照模板的要求填写提交信息,如果没有就不让其执行接下来的git push命令。

2.解决方案

2.1 技术可行性

2.1.1 如何实现

其实当我们创建了一个Git的本地仓库后,项目的根目录下看到一个.git文件夹,在文件夹下的hooks目录下有很多的.sample 为后缀的文件,

如下所示:

这些文件就是我们要改造的脚本,这个以.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 命令后就会出现下中的模板

[]

提交编辑界面:这里需要重点注意下,如上所示,在编辑器的最上面会有一个空格,这个空格需要我们手动删除,然后再填写我们的提交信息。

若是无法编辑,请将输入法切换为英文,按下键盘的i键,进入编辑模式,要保存的时候,切换输入法到英文,然后按下esc键,可以按下 shift+zz 组合键直接保存,或者按下shift + : 进入指令模式,再输入wq,回车就行了,放弃则输入q!

删除空格后,第一行会显示黄色,如下:

[]

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

提交成功会展示:

[]

失败会显示

[]

标出的部分,就是提交规范文档,让开发者可以在失败的时候通过这个文档查看提交规范。

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

(1)本地配置好了后,我们就可以把prepare-commit-msg和commit-msg两个脚本放到你的项目根目录下

[]

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

[]

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 模板改造完后,我们的提交记录就会变得很规整了

[]

3.总结

Git Hook技术可以用来实现很多功能,比如在push操作之前想做一些其他操作,和Java的hook技术差不多,都是希望执行某个操作之前或者之后先执行我们定义的操作,使用这个技术可以做代码的规范验证,提交模板的定义,模板的校验等功能,更多的功能后面用到的时候再做分享。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • idea中实用的git操作问题小结(撤回commit,撤回push、暂存区使用)

    idea中实用的git操作问题小结(撤回commit,撤回push、暂存区使用)

    我们在开发过程中经常遇到commit代码后,发现还有需要修改的地方又不想多次commit,此时如果不想敲git命令,可以利用idea实现commit撤回,下面给大家分享idea中实用的git操作问题小结,感兴趣的朋友跟随小编一起看看吧
    2024-08-08
  • git fetch和git pull的区别解析

    git fetch和git pull的区别解析

    git fetch是将远程主机的最新内容拉到本地,用户在检查了以后决定是否合并到工作本机分支中,这篇文章主要介绍了git fetch和git pull的区别,需要的朋友可以参考下
    2023-01-01
  • Git基础学习之分支操作的示例详解

    Git基础学习之分支操作的示例详解

    这篇文章主要为大家详细介绍了Git基础学习中分支的基本操作,文中的示例代码讲解详细,对我们了解Git有一定的帮助,感兴趣的小伙伴可以跟随小编一起学习一下
    2022-10-10
  • 将Sublime Text 设置成中文版的完整教程

    将Sublime Text 设置成中文版的完整教程

    这篇文章主要介绍了将Sublime Text 设置成中文版的完整教程,需要自己添加之后才会有这一项,对Sublime Text中文版设置方法感兴趣的朋友一起看看吧
    2022-01-01
  • transform实现HTML5 video标签视频比例拉伸实例详解

    transform实现HTML5 video标签视频比例拉伸实例详解

    这篇文章主要介绍了transform实现HTML5 video标签视频比例拉伸的相关资料,需要的朋友可以参考下
    2016-09-09
  • git 入门教程之本地仓库和远程仓库的本质介绍

    git 入门教程之本地仓库和远程仓库的本质介绍

    本地仓库和远程仓库在本质上没有太大区别,只不过一个是本地电脑,一个是远程电脑.这篇文章主要介绍了git 入门教程之本地和远程仓库的本质介绍,需要的朋友可以参考下
    2020-08-08
  • 程序员学英语的一个方法

    程序员学英语的一个方法

    这篇文章主要介绍了程序员学英语的一个方法,程序员学习英语是很有必要的,只要坚持下去,相信必有收获,需要的朋友可以参考下
    2014-08-08
  • 深度学习开源框架基础算法之傅立叶变换的概要介绍

    深度学习开源框架基础算法之傅立叶变换的概要介绍

    今天小编就为大家分享一篇关于深度学习开源框架基础算法之傅立叶变换的概要介绍,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12
  • 详解Git 的 rebase 命令使用方法

    详解Git 的 rebase 命令使用方法

    这篇文章主要介绍了Git 的 rebase 命令使用方法,接下来,我们使用rebase命令,其命令一般形式为git rebase feature,即表示在 master 分支上执行rebase命令,将 feature 分支的代码合并到 master 分支,本文给大家介绍的非常详细,需要的朋友可以参考下
    2022-05-05
  • 关于图片存储格式的整理(BMP格式介绍)

    关于图片存储格式的整理(BMP格式介绍)

    BMP文件的图像深度可选lbit、4bit、8bit及24bit。BMP文件存储数据时,图像的扫描方式是按从左到右、从下到上的顺序。由于BMP文件格式是Windows环境中交换与图有关的数据的一种标准,因此在Windows环境中运行的图形图像软件都支持BMP图像格式
    2016-01-01

最新评论