💡 如何巧用 Git Hook,解決代碼提交中的代碼規範性、衝突和錯誤以及工作流程問題?
近日,在極狐Tech Talk 直播上,極狐(GitLab) 後端工程師田魯分享了自己的實踐經驗。以下內容整理自本次直播,你也可以點擊文末「閲讀原文」觀看視頻回放。Enjoy~
在開發過程中,開發人員提交代碼後,需要繼續做很多工作,因此我們不由萌生一個問題:是否可以把一些工作前置處理,減少等待時間?
首先,我們先回顧一下常見的代碼流程:
1. 開發人員在本地編寫代碼之後,執行 Git Commit 操作 ,保存本地倉庫;
2. 將代碼推送到遠端服務器,觸發 CI Pipeline,執行 Pipeline 中各階段任務:Build、Unit test、Integration test;
3. 執行 CD Pipeline 階段任務:Review、Staging、Production。
在該流程中,若在本地發現問題,修復起來時間相對較短;若在遠程執行 Pipeline 後才發現問題,則修復時間較長,並且增加了服務器的壓力。
那麼是否可以將一些工作提前,如在中間部分(如上圖)完成來提高本地效率,縮短開發流程呢?如題所言“向前一步”,即把原本在 CI 中執行的部分工作,放在本地執行。
代碼流程中的後置處理之痛
常見代碼開發過程中,通常依賴於後置處理,即開發人員的代碼提交到 Git 上以後,運行 CI/CD 或者 Code Review 過程中才發現常見問題,包括:
- 代碼規範 → 花大量時間溝通達成一致;
- 衝突與錯誤 → 提交後發現與主分支衝突,需要重複修改代碼和提交;
- 敏感誤提交 → 可能造成安全事故;
- 缺少自動化任務 → 手動執行,容易遺忘。
這樣既浪費了 CI/CD 資源,也花費了不必要的時間,導致開發效率低。
舉個🌰,如下圖極狐GitLab 中的 Pipelines,在構建作業 → 測試 → 發佈的環節中,我們需要等上傳測試後才能發現錯誤,接着在本地修改,再把 Pipeline 推送上來,才能確認這個錯誤是否被修復;若沒有修復,則需要重複修改,直至修復完成,這個過程耗費很多時間。
可能大家會想到,對團隊成員進行口頭約束,或從制度上要求開發人員必須自己做檢測,但這些幾乎是流於形式。
那麼,極狐GitLab 如何處理解決這些問題的?
極狐GitLab 自動化流程落實前置處理
極狐GitLab 通過自動化流程,高效落實開發工作,讓團隊協作更流暢。
- 代碼規範性問題
在提交代碼前,運行代碼風格檢查和自動化測試等腳本,幫助開發人員發現並修復代碼中的規範性問題,從而保證代碼的質量和可維護性。 - 衝突和錯誤問題
在提交代碼前運行 Git Hook,幫助開發人員避免將錯誤或不規範的代碼推送到代碼倉庫中,從而減少代碼衝突和錯誤。 - 工作流程問題
開發人員規範化 Git 工作流程,提高工作效率和協作效果。通過配置 Git Hook,可以自動化執行代碼檢查、測試、構建和部署等任務,避免手動操作繁瑣和出錯。
極狐GitLab 在具體實踐中逐步完善了該自動化流程,從而確保研發任務能更有效執行。這部分在極狐GitLab 的文檔裏也有更具體説明,感興趣的小夥伴可以查閲我們的資源與文檔。
前置處理的關鍵方法:Git Hook
與許多其他版本控制系統一樣,Git 有一種方法可以在發生某些重要操作時,觸發自定義腳本,即 Git Hook(Git 鈎子)。
當我們初始化一個項目之後,.git 目錄下有一個 hooks 目錄,可以看到上圖左側有很多執行任務,比如 pre-commit,代表在運行這些命令之後或之前,會進行一些校驗和檢測來執行相應任務。
Git Hook 分為兩部分:本地和遠程,如下圖所示:
本地 Git Hook,由提交和合並等操作觸發:
- 比如代碼發生變更,進行 git add,把 message 進行 commit changes;
- 當 git commit 時,就會執行一個鈎子叫 pre-commit(準備提交鈎子)。
遠程 Git Hook,運行在網絡操作上,例如接收推送的提交:
- 在 commit 之後,要推送到遠端,此時有一個叫 pre-push 鈎子,把信息推送 git 倉庫;
- 在遠程階段,極狐GitLab 相當於一個遠程倉庫。如圖有很多倉庫,分別承擔不同功能,比如 pre-receive ,主要在服務器端接收通過本地推上來代碼,然後 update 相關代碼,post-receive 説明代碼接受成功,同時有一個服務器鈎子執行。
在這裏,我們主要關注本地 hook,比如説 pre-message 和 pre-push,因此我們會藉助這些工具來實現規範化代碼內容。
提前進行代碼規範檢測
極狐GitLab 是一個非常大的代碼倉庫,包含前端代碼、後端代碼,還有運維相關代碼:
- 前端代碼如 ESlint、Jsonlint、HAML-lint、Markdown-lint;
- Ruby 相關的如 RuboCop、Stylelint;
- Yaml 相關的如 Yaml-lint。
當然也支持不同語言項目,像 Python、Java 或者其它編程語言,也會有相應代碼規範要求,可以自己添加。
每個 Lint 都會去檢測代碼中的變動,從而檢測代碼是否符合預期。只有符合預期的代碼,才能夠推送進來,避免代碼提交之後,再發現代碼規範問題,在反覆修改上浪費時間。
這就好比整個代碼倉庫是房子,代碼是水,Lint 相當於過濾器,必須讓這些代碼經過過濾後,才能從水龍頭流出,成為生活用水。
提前進行代碼安全檢測
下圖展示的是 GitHub 安全事故:很多人在測試或調試代碼過程中,把一些 Token 放在裏面,無意識地推送到倉庫中,導致 API 和加密密鑰泄露,這很容易被人發現和利用,進而造成巨大損失。
極狐GitLab 十分注重代碼安全,我們必須想辦法阻止開發人員將密鑰提交到倉庫,也就是必須在 Commit 之前,阻止開發人員把密鑰信息給放到 Git 歷史記錄中。
那麼,常見的安全代碼檢測工具有哪些?這裏給大家提供一個參考,就是 Gitleaks。
Gitleaks 是一個 SAST 靜態代碼檢測工具,檢測代碼中常見的 Secret、Token、Password 等內容,生成 Secret 檢測報告產物,避免誤提交,提高研發安全性。
提前進行自動化內容檢測
上述代碼規範檢測、代碼安全檢測,都是在代碼提交前,及時發現問題和解決問題,提升代碼質量和安全性。自動化內容檢測偏向於常規性內容檢測,例如:
- gettext:查找未翻譯的內容,提示開發人員及時翻譯;
- docs-metadata:提醒開發人員為文本添加描述等;
- graphql-doc:檢測 graphql 的 doc 是否完整;
自動化內容檢測避免代碼提交到在服務器後再去修改內容,也是提高開發效率的手段之一。
上述 3 個步驟放在本地開發階段執行,基於以下原因,開發效率就會有很大提升,甚至整個運行時間降低 50%,同時更高效地提升了代碼質量:
- 本地運行速度快;
- 及時發現問題,減少溝通協作成本;
- 節省 Code Review 時間;
- 節省 CI/CD 運行資源。
友好的 Git Hook 管理工具:Lefthook
我們可以使用 Git Hook 裏的 bash 腳本來編寫,比如前面提到的 Eslint、Stylelint 等,但是這種方式有個比較大的缺點:無法放在倉庫中,則無法看到變更歷史,也不方便分發,而且可能不是每個開發人員都熟悉腳本的開發。
因此,我們可能需要更友好的 Git Hook 管理工具,這裏推薦工具:Lefthook。
什麼是 Lefthook?
Lefthook 是一個開源的 Git Hook 管理工具,幫助開發人員自動化和規範化 Git 工作流程。
Lefthook 具備以下特點:
1. 支持多種編程語言:包括 Python、JavaScript、Ruby、Go、Java 等;
2. 簡單易用:輕鬆安裝和配置,使用過程也非常簡單;
3. 高靈活性:允許用户在 Git Hook 中使用任何語言和工具,而不僅僅是 shell 腳本;
4. 高可擴展性:可與其他工具和系統集成,比如 CI/CD 工具、代碼檢查工具、自動化測試工具等;
5. 支持跨平台:支持 macOS、Linux 和 Windows 等多個平台。
如何使用 Lefthook?
前文介紹了本地開發的前置一步,接下來通過實例讓大家體會一下在前置處理中,如何使用 left hook 處理代碼的風格安全問題。
上圖是我第一次編輯的一段 Ruby 代碼:通過 ChatGPT 抓取 GitHub issue 的一個內容。可以看到,acces-token 是一個環境變量,生成一個client 接口,接着我們去抓取相關 issue 信息,最後把它們打印出來。
這段代碼無論從風格上還是從安全性上來説,都是一個很簡單的內容。
假設本地開發人員對這段代碼進行了二次編輯,他發現設置本地變量比較麻煩,直接把密鑰寫在代碼中(如上圖。密鑰為隨機值),同時還把代碼風格打亂了,空了很多多餘行,換行也是往後對齊,導致整個代碼亂糟糟,不符合規範。
把這段代碼推送到 CI 上,就會被檢測出問題,或者 Code Review 發現這些Token 不應該上傳,但這樣屬於事後處理,實際上,我們應該在提交之前處理掉這些問題。
那麼我們看下 Lefthook 的配置, Lefthook 是類似一個 yml 的文件的配置。如下圖,這裏有一個 pre-push 的 hook,還有推送前的一個命令叫 pre commit。這裏我們着重講講 pre-commit。
pre-commit 它運行兩個方面:
1. Rubocop 風格檢測:對 .rb 後綴的文件進行入庫,檢測是否符合規範;
2. 密鑰檢測:檢測文件中是否發生了密碼的泄露。
當我們在 commit 時,就會運行這兩個命令,檢測提交的代碼內容。
檢測上圖這段糟糕的的代碼時,看到執行鈎子 pre-commit 後的效果:
- 密鑰檢測提醒第七行有一個 api key 泄露,確實左邊第七行用了一個明文密鑰;
- 風格檢測提醒 15-17 行是多餘空行,第 25 行寫法不符合規範。
從而這段代碼報錯了,阻止 commit 的提交。
發現這些問題之後,就可以直接在本地去修復了,不用等待 CI/CD 時間;修復完再次提交,就成功了,可以看到 CI/CD 正常運行,讓 CI/CD 在 測試期間也能正常通過,效率就大大提高了。
除了這些內容,我們還會進行一些常規檢測,比如在 Lefthook 配置裏,有一個叫 Ruby 代碼風格檢測工具 Rubocop,有一些命令可以修復大部分錯誤內容,我們也可以加入一些自定義命令,如出現問題,自動修復並推送到服務後,給釘釘發送信息等。
極狐GitLab 中,大概有十幾個 Lefthook 命令,在開發過程中自動發現常見問題並解決。
總結
很多時候,造成效率低下的原因,是發現問題的時機太晚,Git Hook 在本地就能幫助我們解決代碼規範問題、代碼安全問題,並通過自定義腳本內容來自動執行,減少CI/CD、Code Review 時間,整體提升開發效率。