使用Git Hook技術(shù)定義和校驗(yàn)代碼提交模板方式
1.背景
使用Git做項(xiàng)目的版本控制時(shí),在版本系統(tǒng)中會(huì)有很多的代碼的提交記錄,我們使用git log命令就會(huì)得到如下中的提交記錄:

當(dāng)我們的項(xiàng)目比較簡(jiǎn)單,規(guī)模較小、開發(fā)人員也只有一兩個(gè)的時(shí)候,其實(shí)可以不用定義代碼的提交記錄模板,但是當(dāng)我們的項(xiàng)目開始變得龐大,有很多的開發(fā)者都在參與開發(fā)的時(shí)候,我們會(huì)發(fā)現(xiàn)每個(gè)人提交的信息都是千奇百怪的,出現(xiàn)了一個(gè)問題,要定位具體的提交時(shí)更是如大海撈針。特別痛苦。
所以Git提供了代碼提交記錄模板,和對(duì)提交記錄模板的驗(yàn)證,讓每個(gè)提交代碼的開發(fā)者按照模板填寫提交的信息,提交后再驗(yàn)證下開發(fā)者是否按照模板的要求填寫提交信息,如果沒有就不讓其執(zhí)行接下來的git push命令。
2.解決方案
2.1 技術(shù)可行性
2.1.1 如何實(shí)現(xiàn)
其實(shí)當(dāng)我們創(chuàng)建了一個(gè)Git的本地倉(cāng)庫后,項(xiàng)目的根目錄下看到一個(gè).git文件夾,在文件夾下的hooks目錄下有很多的.sample 為后綴的文件,
如下所示:

這些文件就是我們要改造的腳本,這個(gè)以.sample后綴結(jié)束的腳本文件是不會(huì)執(zhí)行的,如果需要執(zhí)行,我們需要去掉.sample后綴。
我們要實(shí)現(xiàn)的功能是定義Git提交模板和校驗(yàn)?zāi)0宓恼_性。
所以我們可以參考prepare-commit-msg.sample(提交模板)和commit-msg.sample(驗(yàn)證模板)完成我們的功能,修改完這個(gè)模板后我們就可以使用模板了,當(dāng)我們需要使用命令git commit 提交代碼時(shí),在出現(xiàn)的提交信息編輯器中會(huì)出現(xiàn)我們?cè)?code>prepare-commit-msg腳本中定義好的模板,我們填寫完模板后保存模板,這時(shí)會(huì)使用commit-msg腳本對(duì)模板做校驗(yàn)。這樣的話我們的本地提交代碼就能使用我們定義好的模板了。
2.1.2 如何同步配置到項(xiàng)目中其他開發(fā)者
現(xiàn)在還有一個(gè)問題,就是這些配置都是在我們的本地,項(xiàng)目中的其他開發(fā)者并沒有這個(gè)環(huán)境,我們?nèi)绻屗麄內(nèi)ヅ渲蔑@然不合適,因?yàn)橛械娜丝赡懿粫?huì)搭理你。所以我們需要做到讓開發(fā)者無感知的就裝上了我們的環(huán)境,原理其實(shí)就是我們將模板提交到代碼倉(cāng)庫中,然后通過腳本將配置的模板拷貝到用戶的".git/hooks"目錄下,當(dāng)用戶觸發(fā)某個(gè)操作時(shí),就執(zhí)行腳本。本文我們以Android項(xiàng)目為例子,使用Gradle腳本,當(dāng)用戶執(zhí)行構(gòu)建操作的時(shí)候,我們執(zhí)行配置提交模板的腳本
2.2 實(shí)現(xiàn)方案
2.2.1 提交模板的腳本示例
在.git/hooks目錄下,復(fù)制prepare-commit-msg.sample文件,重命名為prepare-commit-msg(注意這里沒有“.sample后綴名”),我們定義一個(gè)模板:
- 項(xiàng)目名稱: [MountTai] 部門名稱: [] 禪道BUGID: [無]
- 原因分析: {}
- 解決方案: {}
prepare-commit-msg:(腳本是用perl語言和shell語言搭配寫的,比較簡(jiǎn)單就不細(xì)講了),邏輯就是在開發(fā)者進(jìn)入編輯器之前,往編輯器寫入我們的模板。
這樣編輯器打開后顯示的就是我們寫的模板啦。
#!/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 "項(xiàng)目名稱: [MountTai] 部門名稱: [] 禪道BUGID: [無]\n
#部門名稱: Android開發(fā)部 / 三維軟件部 \n\n原因分析: {}\n解決方案: {}\n" if /^#/ && $first++ == 0' "$1" ;;
*) ;;
esac
這個(gè)文件編寫好后,直接放到.git/hooks目錄下,然后我們執(zhí)行git commit 命令后就會(huì)出現(xiàn)下中的模板
![[]](http://img.jbzj.com/file_images/article/202311/2023111510572316.png)
提交編輯界面:這里需要重點(diǎn)注意下,如上所示,在編輯器的最上面會(huì)有一個(gè)空格,這個(gè)空格需要我們手動(dòng)刪除,然后再填寫我們的提交信息。
若是無法編輯,請(qǐng)將輸入法切換為英文,按下鍵盤的i鍵,進(jìn)入編輯模式,要保存的時(shí)候,切換輸入法到英文,然后按下esc鍵,可以按下 shift+zz 組合鍵直接保存,或者按下shift + : 進(jìn)入指令模式,再輸入wq,回車就行了,放棄則輸入q!。
刪除空格后,第一行會(huì)顯示黃色,如下:
![[]](http://img.jbzj.com/file_images/article/202311/2023111510572317.png)
2.2.2 校驗(yàn)?zāi)0迨纠?/strong>
復(fù)制.git/hooks下的commit-msg.sample文件,重命名為commit-msg,然后編寫模板校驗(yàn)規(guī)則,使用正則表達(dá)式驗(yàn)證開發(fā)者提交的代碼信息。
下面的邏輯就是獲取提交的信息后,使用正則表達(dá)式去匹配。
成功的話就可以繼續(xù)提交,否則的話提示用戶消息提交格式不合法,重新編輯提交
commit_msg=`cat $1`
msg_re="^(項(xiàng)目名稱|部門名稱|禪道BUGID|原因分析|解決方案)(\(.+\))?: .{1,100}"
if [[ ! $commit_msg =~ $msg_re ]]
then
echo -e "不合法的 commit 消息提交格式,請(qǐng)使用正確的格式:\n
詳情請(qǐng)查看 git commit 提交規(guī)范:https://t3hx1u77li.feishu.cn/docx/CJr7d7aHJofPcYxOA1NcISVBn0d"
# 異常退出
exit 1
fi
提交成功會(huì)展示:
![[]](http://img.jbzj.com/file_images/article/202311/2023111510572318.png)
失敗會(huì)顯示
![[]](http://img.jbzj.com/file_images/article/202311/2023111510572319.png)
標(biāo)出的部分,就是提交規(guī)范文檔,讓開發(fā)者可以在失敗的時(shí)候通過這個(gè)文檔查看提交規(guī)范。
2.2.3 配置同步到項(xiàng)目的其他開發(fā)者腳本示例
(1)本地配置好了后,我們就可以把prepare-commit-msg和commit-msg兩個(gè)腳本放到你的項(xiàng)目根目錄下
![[]](http://img.jbzj.com/file_images/article/202311/2023111510572320.png)
(2)創(chuàng)建一個(gè)gradle腳本,做環(huán)境拷貝工作
![[]](http://img.jbzj.com/file_images/article/202311/2023111510572321.png)
Git配置提交模板和校驗(yàn)?zāi)0宓膅radle腳本示例:
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
}
腳本的意思就是當(dāng)我們運(yùn)行Android的構(gòu)建時(shí),就會(huì)執(zhí)行我們的這個(gè)腳本,把項(xiàng)目中的prepare-commit-msg和commit-msg腳本拷貝到開發(fā)者的.git/hooks目錄下,然后開發(fā)者就可以使用提交模板和驗(yàn)證功能了
提交代碼的時(shí)候若是使用形界面,可以把模板復(fù)制到界面中提交
![[]](http://img.jbzj.com/file_images/article/202311/2023111510572322.png)
Git 模板改造完后,我們的提交記錄就會(huì)變得很規(guī)整了
![[]](http://img.jbzj.com/file_images/article/202311/2023111510572323.png)
3.總結(jié)
Git Hook技術(shù)可以用來實(shí)現(xiàn)很多功能,比如在push操作之前想做一些其他操作,和Java的hook技術(shù)差不多,都是希望執(zhí)行某個(gè)操作之前或者之后先執(zhí)行我們定義的操作,使用這個(gè)技術(shù)可以做代碼的規(guī)范驗(yàn)證,提交模板的定義,模板的校驗(yàn)等功能,更多的功能后面用到的時(shí)候再做分享。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
301重定向代碼合集(iis,asp,php,asp.net,apache)
腳本之家將SEO工作中所需要的301轉(zhuǎn)向代碼進(jìn)行了整理,收藏并分享,以備查閱。2011-02-02
gitlab項(xiàng)目如何修改主分支main為master以及可能遇到的問題詳解
本文詳細(xì)介紹了如何將Git倉(cāng)庫的主分支名稱從main修改為master,包括本地和遠(yuǎn)程倉(cāng)庫的更改步驟,以及如何在GitLab上更改默認(rèn)分支和刪除受保護(hù)分支2024-11-11
VSCode 使用Settings Sync同步配置(最新版教程,非常簡(jiǎn)單)
這篇文章主要介紹了VSCode 使用Settings Sync同步配置(最新版教程,非常簡(jiǎn)單),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11
vscode 左側(cè)擴(kuò)展活動(dòng)欄內(nèi)容消失的問題及解決方法
vscode左側(cè)活動(dòng)欄默認(rèn)會(huì)有 一些內(nèi)容,今天一不小心,不知道怎么的,將部分內(nèi)容搞沒了,vscode 左側(cè)擴(kuò)展活動(dòng)欄內(nèi)容消失了怎么辦,下面給大家分享本文幫助大家快速解決,感興趣的朋友一起看看吧2021-08-08
關(guān)于Idea向GitHub push代碼時(shí)一直重復(fù)提示輸入用戶名和密碼的問題
這篇文章主要介紹了關(guān)于Idea向GitHub push代碼時(shí)一直重復(fù)提示輸入用戶名和密碼的問題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01

