在Git上如何強推代碼規范關注微信公眾號:大轉轉FE。 一個有趣的前端團隊~ 關注她 6 人贊同了該文章 引言最近參加了“前端規范制定topic”小組,小組成員一起制定了html、css、js、es6、vue和react等規范,但規范制定好了怎么進行推廣去強制執行呢,已知我們的項目都是用git做管理的,所以馬上想到在git上做文章,本文講述的就是如何在git上推行代碼強校驗。 git知識點說到git,我們先來了解下平時項目中不是很關注的幾個git概念. git倉庫 git是分布式版本管理系統,可以有多個代碼倉庫,所有參與項目的開發者都可以擁有自己的本地倉庫,每一個本地倉庫都是一個完整的版本庫,即使不聯網,也可以任意的進行開發、創建分支、commit和查看版本的歷史提交記錄等。 但每個人都在自己的本地倉庫開發,怎么做到代碼共享和同步呢?在我們的項目中,通常都會建立一個大家都可以訪問的共享倉庫,這個共享倉庫放在一個專門的線上服務器上,我們也叫它遠程倉庫。遠程倉庫和本地倉庫的唯一差別就在于它是裸倉庫,就是不包含任何工作目錄,僅僅是由 “.git” 目錄組成的。它作為服務器倉庫供各開發者push、pull數據,實現數據共享和同步,不保存文件,只保存歷史提交的版本信息等。 ![]() git存儲方式 說完git倉庫,我們來了解下git的存儲方式。git存儲數據更像是把數據看作是對小型文件系統的一組快照,每次提交更新或者是保存項目狀態時,它主要對現有的文件制作一個快照并保存這個快照的索引。這個“快照”就是git對象,而“快照的索引”就是對象名。所有用來表示項目歷史信息的文件,都是通過一個40字符的(40-digit)“對象名”來索引的。對象名看起來像這樣的:26e5847434caa7597c4088de8ecab9cd567957d1。 在git里,每一個“對象名”都是對“對象”內容做 SHA-1哈希計算得來的, SHA-1是一種密碼學的hash算法,這樣在每個倉庫中不同內容的對象就會有不同的對象名。git有四種類型的對象:"blob"、"tree"、 "commit" 和”tag”:
所以下面所描述的獲取文件信息基本上都是通過各種git命令操作hash對象名來獲取的,這也是為什么在這里介紹“git存儲方式”的原因,方便大家更深刻的了解git命令。 作用域 由git倉庫的定義可以看出,本地倉庫因為是本地的,任何能接觸得到倉庫的人都可以進行修改、刪除等,所以本地倉庫不適合做代碼強校驗。那只能考慮遠程倉庫了,可以當用戶push推送的時候,校驗代碼,如果不符合規范,就拒絕這次提交,雖然你不能阻止開發者寫出糟糕的代碼,但可以防止這些代碼流入官方的代碼庫。 git鉤子 好了,確定了規范在服務端倉庫上來強推行,但怎么做到當用戶push動作觸發的時候去做一下代碼強校驗呢,經過調研發現,git鉤子正好解決了我們的這個問題。 什么是git鉤子呢?git鉤子是在git倉庫中特定重要動作發生時自動運行的腳本,它可以讓你自定義git內部的行為,在開發周期中的關鍵點觸發自定義的行為。這樣來說,git鉤子就可以幫我們來推行規范了。 git鉤子到底什么樣呢,它存在于每個git倉庫的.git/hooks目錄中,當你觀察.git/hooks時,你會看到下面這樣的文件: ![]() hooks目錄下展示的鉤子并不全,這里帶simple后綴的只是git的大部分鉤子,.sample拓展名防止它們默認被執行,想要運行一個鉤子,去掉后綴名或者在git官網查看相應鉤子名稱添加新文件即可。 鉤子分類
鉤子語言
git服務端鉤子由上面的git知識點一步步看下來,我們就可以確定了代碼校驗合適的地方是在服務端鉤子上,但服務端鉤子也有好多,我們的代碼規范要在哪個鉤子做比較合適呢,接來下就具體介紹下服務端最有用的3個鉤子,并找出一個適合我們的鉤子。
這個腳本在git push向遠程倉庫推送操作時,最先被調用。它沒有參數,但是可以從標準輸入獲取一系列的推送引用。如果它以非零值退出,所有的推送內容都不會被接受,所以這是強制推行開發規范的好地方。
update腳本和pre-receive腳本十分類似,不同之處在于它會為每一個準備更新的分支各運行一次。假如推送者同時向多個分支推送內容,pre-receive只運行一次,相比之下update則會為每一個被推送的分支各運行一次。它不會從標準輸入讀取內容,而是會接受三個參數,這三個參數信息和pre-receive在標準輸入讀取信息相同。如果update腳本以非零值退出,只有相應的那一個引用會被拒絕;其余的依然會被更新。
post-receive腳本在成功推送后被調用,可以用來更新其他系統服務或者通知用戶,它接受與 pre-receive相同的標準輸入數據。它的用途包括給某個郵件列表發信,通知持續集成(continous integration)的服務器,或者更新問題追蹤系統(ticket-tracking system)等。 服務端推送成功后調用的鉤子不止post-receive這一個,如上面.git/hooks圖中的post-update也是其中之一,但是為什么不介紹post-update呢?原因是它的輸入獲取值太單一,post-receive更像是post-update的超級集合,所以推送成功后的調用我們一般用post-receive。 我們經常用到的gitlab中的web hook就綁定了這個鉤子,當然web hook是綁定了好幾個不同的鉤子的,post-receive只是其中一個,如下圖的web hook的中的Push events事件觸發的就是.git/hooks中的post-receive腳本 ![]() 分析這三個鉤子,我們顯然選push成功前調用的鉤子,那到底是選pre-receive還是update呢?考慮到我們的項目很少有一次push多個分支的場景,最終選了pre-receive鉤子來做我們的代碼強校驗。 在pre-receive鉤子里做代碼校驗鉤子選擇好了,接下來就是怎么做了,下面是一個簡單的流程圖,具體為從標準輸入中獲取三個值,分別是推送前的引用指向內容的SHA-1值,用戶準備推送內容的SHA-1值和分支名,我再代碼里分別用變量oldhash,newhash和branch來表示這三個值,下面有用到。根據這三個值用git命令分別獲取用戶信息和提交的增量文件,把這些文件推送到eslint服務上進行代碼校驗,校驗成功就直接push通過;不成功則在客戶端返回校驗結果,push不通過。 ![]() 根據上面的描述,重點介紹下怎么獲取用戶信息和增量文件
獲取用戶信息的目的是傳給eslint服務端,在服務端可以給分析用戶的行為及給用戶發送郵件等 這個命令可以定制化格式只獲取用戶的信息
定制化后運行的結果是下面這樣的,可以獲取提交者的信息: ![]()
增量文件取得是本次推送引用指向內容的SHA-1值和推送前的引用指向內容的SHA-1值中間的差值。命令如下,其中 --name-status是只取差異文件的名字和狀態值 為什么不直接取本次推送引用指向內容的SHA-1值而取差值呢,原因是上次推送和本次推送中間可能隔了好幾個commit,每一個commit對象都會生成一個唯一的SHA-1哈希字串的。
運行后得到的結果是: ![]() 后面的就是怎么獲取文件及和eslint服務通訊的問題了,在這里不是重點就略過了... 總結本文可以說是我接到任務后,從只了解git的git pull、git clone、git push等幾個常用命令到怎么在git上實現我們的需求的一個探索過程,希望里面的介紹對不是很熟悉git的同學有點幫助,另外也簡單介紹了下我們強推規范的大致流程。后續會繼續研究下gitlab和git鉤子的關聯關系。 |
|
來自: bananarlily > 《IT》