使用Git Hook技術(shù)定義和校驗(yàn)代碼提交模板方式
1.背景
使用Git做項(xiàng)目的版本控制時(shí),在版本系統(tǒng)中會(huì)有很多的代碼的提交記錄,我們使用git log命令就會(huì)得到如下中的提交記錄:
當(dāng)我們的項(xiàng)目比較簡(jiǎn)單,規(guī)模較小、開(kāi)發(fā)人員也只有一兩個(gè)的時(shí)候,其實(shí)可以不用定義代碼的提交記錄模板,但是當(dāng)我們的項(xiàng)目開(kāi)始變得龐大,有很多的開(kāi)發(fā)者都在參與開(kāi)發(fā)的時(shí)候,我們會(huì)發(fā)現(xiàn)每個(gè)人提交的信息都是千奇百怪的,出現(xiàn)了一個(gè)問(wèn)題,要定位具體的提交時(shí)更是如大海撈針。特別痛苦。
所以Git提供了代碼提交記錄模板,和對(duì)提交記錄模板的驗(yàn)證,讓每個(gè)提交代碼的開(kāi)發(fā)者按照模板填寫(xiě)提交的信息,提交后再驗(yàn)證下開(kāi)發(fā)者是否按照模板的要求填寫(xiě)提交信息,如果沒(méi)有就不讓其執(zhí)行接下來(lái)的git push
命令。
2.解決方案
2.1 技術(shù)可行性
2.1.1 如何實(shí)現(xiàn)
其實(shí)當(dāng)我們創(chuàng)建了一個(gè)Git的本地倉(cāng)庫(kù)后,項(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腳本中定義好的模板,我們填寫(xiě)完模板后保存模板,這時(shí)會(huì)使用commit-msg
腳本對(duì)模板做校驗(yàn)。這樣的話(huà)我們的本地提交代碼就能使用我們定義好的模板了。
2.1.2 如何同步配置到項(xiàng)目中其他開(kāi)發(fā)者
現(xiàn)在還有一個(gè)問(wèn)題,就是這些配置都是在我們的本地,項(xiàng)目中的其他開(kāi)發(fā)者并沒(méi)有這個(gè)環(huán)境,我們?nèi)绻屗麄內(nèi)ヅ渲蔑@然不合適,因?yàn)橛械娜丝赡懿粫?huì)搭理你。所以我們需要做到讓開(kāi)發(fā)者無(wú)感知的就裝上了我們的環(huán)境,原理其實(shí)就是我們將模板提交到代碼倉(cāng)庫(kù)中,然后通過(guò)腳本將配置的模板拷貝到用戶(hù)的".git/hooks"目錄下,當(dāng)用戶(hù)觸發(fā)某個(gè)操作時(shí),就執(zhí)行腳本。本文我們以Android項(xiàng)目為例子,使用Gradle腳本,當(dāng)用戶(hù)執(zhí)行構(gòu)建操作的時(shí)候,我們執(zhí)行配置提交模板的腳本
2.2 實(shí)現(xiàn)方案
2.2.1 提交模板的腳本示例
在.git/hooks
目錄下,復(fù)制prepare-commit-msg.sample
文件,重命名為prepare-commit-msg
(注意這里沒(méi)有“.sample
后綴名”),我們定義一個(gè)模板:
- 項(xiàng)目名稱(chēng): [MountTai] 部門(mén)名稱(chēng): [] 禪道BUGID: [無(wú)]
- 原因分析: {}
- 解決方案: {}
prepare-commit-msg:
(腳本是用perl語(yǔ)言和shell語(yǔ)言搭配寫(xiě)的,比較簡(jiǎn)單就不細(xì)講了),邏輯就是在開(kāi)發(fā)者進(jìn)入編輯器之前,往編輯器寫(xiě)入我們的模板。
這樣編輯器打開(kāi)后顯示的就是我們寫(xiě)的模板啦。
#!/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)目名稱(chēng): [MountTai] 部門(mén)名稱(chēng): [] 禪道BUGID: [無(wú)]\n #部門(mén)名稱(chēng): Android開(kāi)發(fā)部 / 三維軟件部 \n\n原因分析: {}\n解決方案: {}\n" if /^#/ && $first++ == 0' "$1" ;; *) ;; esac
這個(gè)文件編寫(xiě)好后,直接放到.git/hooks
目錄下,然后我們執(zhí)行git commit
命令后就會(huì)出現(xiàn)下中的模板
提交編輯界面:這里需要重點(diǎn)注意下,如上所示,在編輯器的最上面會(huì)有一個(gè)空格,這個(gè)空格需要我們手動(dòng)刪除,然后再填寫(xiě)我們的提交信息。
若是無(wú)法編輯,請(qǐng)將輸入法切換為英文,按下鍵盤(pán)的i
鍵,進(jìn)入編輯模式,要保存的時(shí)候,切換輸入法到英文,然后按下esc
鍵,可以按下 shift+zz
組合鍵直接保存,或者按下shift + :
進(jìn)入指令模式,再輸入wq
,回車(chē)就行了,放棄則輸入q!
。
刪除空格后,第一行會(huì)顯示黃色,如下:
2.2.2 校驗(yàn)?zāi)0迨纠?/strong>
復(fù)制.git/hooks
下的commit-msg.sample
文件,重命名為commit-msg
,然后編寫(xiě)模板校驗(yàn)規(guī)則,使用正則表達(dá)式驗(yàn)證開(kāi)發(fā)者提交的代碼信息。
下面的邏輯就是獲取提交的信息后,使用正則表達(dá)式去匹配。
成功的話(huà)就可以繼續(xù)提交,否則的話(huà)提示用戶(hù)消息提交格式不合法,重新編輯提交
commit_msg=`cat $1` msg_re="^(項(xiàng)目名稱(chēng)|部門(mén)名稱(chē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ì)展示:
失敗會(huì)顯示
標(biāo)出的部分,就是提交規(guī)范文檔,讓開(kāi)發(fā)者可以在失敗的時(shí)候通過(guò)這個(gè)文檔查看提交規(guī)范。
2.2.3 配置同步到項(xiàng)目的其他開(kāi)發(fā)者腳本示例
(1)本地配置好了后,我們就可以把prepare-commit-msg和commit-msg
兩個(gè)腳本放到你的項(xiàng)目根目錄下
(2)創(chuàng)建一個(gè)gradle腳本,做環(huán)境拷貝工作
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
腳本拷貝到開(kāi)發(fā)者的.git/hooks
目錄下,然后開(kāi)發(fā)者就可以使用提交模板和驗(yàn)證功能了
提交代碼的時(shí)候若是使用形界面,可以把模板復(fù)制到界面中提交
Git 模板改造完后,我們的提交記錄就會(huì)變得很規(guī)整了
3.總結(jié)
Git Hook技術(shù)可以用來(lái)實(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)文章
wap開(kāi)發(fā)中如何有效的利用緩存減少消息的傳送量
由于WAP信道帶寬的限制,我們?cè)诰帉?xiě)WAP應(yīng)用的時(shí)候都希望最大限度地減少消息的傳送量。2010-06-06301重定向代碼合集(iis,asp,php,asp.net,apache)
腳本之家將SEO工作中所需要的301轉(zhuǎn)向代碼進(jìn)行了整理,收藏并分享,以備查閱。2011-02-02VSCode 遠(yuǎn)程登錄開(kāi)發(fā)(帶免密)
這篇文章主要介紹了VSCode 遠(yuǎn)程登錄開(kāi)發(fā)(帶免密),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05gitlab項(xiàng)目如何修改主分支main為master以及可能遇到的問(wèn)題詳解
本文詳細(xì)介紹了如何將Git倉(cāng)庫(kù)的主分支名稱(chēng)從main修改為master,包括本地和遠(yuǎn)程倉(cāng)庫(kù)的更改步驟,以及如何在GitLab上更改默認(rèn)分支和刪除受保護(hù)分支2024-11-11VSCode 使用Settings Sync同步配置(最新版教程,非常簡(jiǎn)單)
這篇文章主要介紹了VSCode 使用Settings Sync同步配置(最新版教程,非常簡(jiǎn)單),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11vscode 左側(cè)擴(kuò)展活動(dòng)欄內(nèi)容消失的問(wèn)題及解決方法
vscode左側(cè)活動(dòng)欄默認(rèn)會(huì)有 一些內(nèi)容,今天一不小心,不知道怎么的,將部分內(nèi)容搞沒(méi)了,vscode 左側(cè)擴(kuò)展活動(dòng)欄內(nèi)容消失了怎么辦,下面給大家分享本文幫助大家快速解決,感興趣的朋友一起看看吧2021-08-08關(guān)于Idea向GitHub push代碼時(shí)一直重復(fù)提示輸入用戶(hù)名和密碼的問(wèn)題
這篇文章主要介紹了關(guān)于Idea向GitHub push代碼時(shí)一直重復(fù)提示輸入用戶(hù)名和密碼的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01