不会写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,不过想一想这样的方法也比上面个人方法高明许多 -.-!

相关文章
相关标签/搜索