git hooks想必不少攻城獅都不陌生,官方對於hooks有詳細的文檔,也有站內網友的文章Git Hooks (1):介紹,GIt Hooks (2):腳本分類,說的很是詳細了,這裏就很少作介紹,這裏主要介紹一下如何寫一個hook。javascript
對git-hooks有一個入門認識的朋友都知道,hooks存放在git倉庫的.git/hooks
目錄下,其中包括不少hooks,這些是在git 倉庫建立的時候自動生成的,後綴名統一都是.sample
,表示這些hooks都是默認不啓用的,當把後綴名去掉以後,就變成了可使用的hook。前端
pre-commit這個hook是在git commit
的時候觸發的hook,這個hook裏面寫了什麼呢?代碼我就不貼了,沒啥勁,主要的幾點就是:java
這是一個shell腳本node
這個腳本運行了一些東西而後退出了git
退出的時候退出的錯誤碼不是肯定的github
這就是一個hook的最基本的組成:在命令行執行git操做的時候,自動執行hooks目錄下相應的可執行腳本,而後根據腳本的退出狀態決定這次操做是否成功。當退出的錯誤碼不爲0的時候,表示失敗,操做終止,不然操做繼續。shell
若是如今有這樣一個場景,在你的git倉庫裏,要求不容許提交dist
目錄,而且經過mocha
的測試,不然不容許提交,用git hook 怎麼作呢?npm
首先,這是在提交的時候的一個限制,因此應該考慮使用pre-commit
這個hook,代碼就不寫了(不會寫shell... Orz),整個過程以下:json
檢查是否有dist
目錄,若是沒有的話下一步,不然退出,錯誤碼置爲1。segmentfault
執行mocha命令進行測試,若是測試所有經過的話,退出,錯誤碼爲0,不然錯誤碼爲1,一樣退出。
這樣,當上述任何一步沒有經過的時候,這個hook就會被終止,git-commit就沒法經過,也就達到了限制提交的目的。
做爲一名普通的前端,兼,一名不太合格的工程師,我對於shell腳本實在是不熟悉,連Linux命令都玩不轉,別說寫出666的shell腳本了,囧~ 因此要另闢巧徑作這件事。
前端仔們對js應該是很是熟練的,因此若是能用js寫hooks,那不就爽了?而Node.JS正好給了咱們但願,感激不盡的話就很少說了,絕對感動到哭!
Node.js寫起腳原本也很是簡單,好比一個最簡單的腳本
#!/usr/bin/env node console.log('Hello World!');
給腳本賦予可執行權限以後就徹底能夠當作shell腳原本跑了,麻麻不再用擔憂我不會shell了。一樣的,在hooks中咱們也能夠這樣用。再舉個栗子
仍是剛纔的場景,不容許有dist
目錄,同時經過全部mocha測試,用Node就能夠這樣寫(此次我能show出代碼了)
#!/usr/bin/env node var fs = require('fs'), spawnSync = require('child_process').spawnSync; if(fs.existsSync('./dist')){ console.log('Commit Abort!Please remove dist directory.'); process.exit(1); } // 使用同步方法spawnSync執行mocha,測試的結果在result.status中,經過爲0,不經過爲1 var result = spawnSync('./node_modules/.bin/mocha',['test']); if(result.status){ console.log('Commit Abort!Test failure.'); } process.exit(result.status);
這就是一個用Node.JS實現的基本的git-hook。
client-side hook的一個問題就是無法在隨着倉庫變更,若是項目成員多的話,每一個人都須要在本身本地添加一次,hooks有變更了更新也比較麻煩。
我我的對這個問題有一個簡單解決方案,我作了一個倉庫git-hooks-node,每次寫好git hooks以後經過本身寫的工具進行build,生成一個相似於安裝器的文件,而後提交到遠程倉庫,如pre-commit.js是hook具體的內容,pre-commit.installer.js是生成的安裝文件,也是一個腳本,github上的每個文件都有相應的raw地址,如這個安裝文件的地址爲raw pre-commit.installer.js,而後mac OS下的用戶就可使用curl
獲取腳本並運行,以下:
curl https://raw.githubusercontent.com/y8n/git-hooks-node/master/xgfe-ma/pre-commit.installer.js | node
安裝效果以下
這樣只要寫好一個hook併發布,項目成員只要知道地址就能夠一鍵安轉(想一想還有點小激動呢)。這樣雖然沒有解決hook不會隨着倉庫移動的問題,但也提供了一種在項目組裏通用一套hook的方案。
husky是GitHub上一個開源項目,它的作法是在npm install
這個模塊的時候自動在.git/hooks
目錄下建立不少hooks,而後再在package.json中指定每個hook的執行腳本,以下
"scripts": { "precommit": "npm test", "prepush": "npm test", "commit-msg": "./validate-commit-msg.js", "...": "..." }
這樣就能夠把hooks隨着項目變更,真正作到項目成員共用一個git hook,但問題就是必須在項目中依賴husky,不過想一想這樣的方法也比上面個人方法高明許多 -.-!