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-msg
和commit-msg
脚本拷贝到开发者的.git/hooks
目录下,然后开发者就能够运用提交模板和验证功用了
提交代码的时分若是运用图形界面,能够把模板复制到界面中提交
Git 模板改造完后,咱们的提交记载就会变得很规整了
3.总结
Git Hook技能能够用来完结许多功用,比如在push操作之前想做一些其他操作,和Java的hook技能差不多,都是希望履行某个操作之前或者之后先履行咱们界说的操作,运用这个技能能够做代码的标准验证,提交模板的界说,模板的校验等功用,更多的功用后面用到的时分再做分享。