不會寫shell的程序員照樣是好前端——用Node.JS實現git hooks

git hooks想必不少攻城獅都不陌生,官方對於hooks有詳細的文檔,也有站內網友的文章Git Hooks (1):介紹,GIt Hooks (2):腳本分類,說的很是詳細了,這裏就很少作介紹,這裏主要介紹一下如何寫一個hook。javascript

一個基本的git hook長什麼樣?

對git-hooks有一個入門認識的朋友都知道,hooks存放在git倉庫的.git/hooks目錄下,其中包括不少hooks,這些是在git 倉庫建立的時候自動生成的,後綴名統一都是.sample,表示這些hooks都是默認不啓用的,當把後綴名去掉以後,就變成了可使用的hook。前端

舉個栗子

圖片描述

pre-commit這個hook是在git commit的時候觸發的hook,這個hook裏面寫了什麼呢?代碼我就不貼了,沒啥勁,主要的幾點就是:java

  1. 這是一個shell腳本node

  2. 這個腳本運行了一些東西而後退出了git

  3. 退出的時候退出的錯誤碼不是肯定的github

這就是一個hook的最基本的組成:在命令行執行git操做的時候,自動執行hooks目錄下相應的可執行腳本,而後根據腳本的退出狀態決定這次操做是否成功。當退出的錯誤碼不爲0的時候,表示失敗,操做終止,不然操做繼續。shell

模擬場景

若是如今有這樣一個場景,在你的git倉庫裏,要求不容許提交dist目錄,而且經過mocha的測試,不然不容許提交,用git hook 怎麼作呢?npm

首先,這是在提交的時候的一個限制,因此應該考慮使用pre-commit這個hook,代碼就不寫了(不會寫shell... Orz),整個過程以下:json

  1. 檢查是否有dist目錄,若是沒有的話下一步,不然退出,錯誤碼置爲1。segmentfault

  2. 執行mocha命令進行測試,若是測試所有經過的話,退出,錯誤碼爲0,不然錯誤碼爲1,一樣退出。

這樣,當上述任何一步沒有經過的時候,這個hook就會被終止,git-commit就沒法經過,也就達到了限制提交的目的。

shell腳本的侷限性——不會寫

做爲一名普通的前端,兼,一名不太合格的工程師,我對於shell腳本實在是不熟悉,連Linux命令都玩不轉,別說寫出666的shell腳本了,囧~ 因此要另闢巧徑作這件事。

前端仔們對js應該是很是熟練的,因此若是能用js寫hooks,那不就爽了?而Node.JS正好給了咱們但願,感激不盡的話就很少說了,絕對感動到哭!

20151004154819_vcYJV.thumb.224_0.jpeg

Node.js寫起腳原本也很是簡單,好比一個最簡單的腳本

#!/usr/bin/env node

console.log('Hello World!');

給腳本賦予可執行權限以後就徹底能夠當作shell腳原本跑了,麻麻不再用擔憂我不會shell了。一樣的,在hooks中咱們也能夠這樣用。再舉個栗子

060cc75c10385343024d82b79513b07ecb808848.jpg

仍是剛纔的場景,不容許有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。

Node.JS的侷限性——不能動

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,不過想一想這樣的方法也比上面個人方法高明許多 -.-!

相關文章
相關標籤/搜索