当前位置: 首页 > 后端技术 > Node.js

使用Node.js编写自己的Git-hooks

时间:2023-04-03 11:10:45 Node.js

TLDR;介绍Githooks的基本开发流程介绍如何使用Node.js编写Githooks,gitpush)触发脚本。hooks主要分为两种:clienthooksserverhooks和clienthooks分为以下几种:typehookname接收参数可以终止操作,sha-1\提交工作流挂钩commit-msgfilepath是提交工作流挂钩post-commit\电子邮件工作流挂钩applypatchmsgmerge文件名是otherclienthookspost-rewrite,post-checkoutandpost-mergecommandname\otherclienthookspre-pushoriginbranhname&headserverhooks主要有三种:hookname接收参数可以终止操作。pre-receivepushreference是updatereference的名称(分支),pre-pushreference指向的内容的SHA-1值,以及用户要推送的内容的SHA-1值post-receivepre-receive与client-sidehooks和server-sidehooks的异同Githooks,不管是client-sidehooks还是server-sidehooks,都放在当前项目的.git/hooks目录下。不同的是,客户端的钩子放在你本地项目的目录下,而服务器端的钩子放在服务器上相应的目录下。我们知道Git相当于一个本地的文件数据库,而.git目录存放的是项目文件的快照以及其他一系列的git信息,而.git目录是不会提交给服务器的,所以放在.git目录下。git/hooks目录客户端脚本也不会被提交。所以如果你想让项目中的其他人使用你的钩子,你需要一个策略来偷偷安装这个钩子或者把实现这个钩子的功能放在服务器端。如何用Nodejs编写钩子钩子存放在Git目录下的hooks子目录中。在大多数项目中就是.git/hooks。当你用gitinit初始化一个新的仓库时,Git默认会在这个目录下放置一些示例脚本。这些脚本除了能够被调用之外,还会暴露被触发时传入的参数。所有示例都是shell脚本,其中一些混合了Perl代码,但任何正确命名的可执行脚本都可以正常工作——您可以用Ruby、Python或其他语言编写它们。这些样本的名称都以.sample结尾,如果你想启用它们,你必须先去掉这个后缀。通过在Git目录的hooks子目录中放置一个正确命名的可执行文件来激活挂钩脚本。稍后我将使用Node.js编写一个钩子,该钩子拒绝提交具有未解决冲突的文件。所需知识储备:会写Javascript,了解一点环境变量知识,了解Nodejsrequire路径规则。冲突归档并一一解决。这个钩子会在提交的时候检查是否有冲突。如果有冲突,会找出所有冲突,提示错误文件后拒绝提交。直接上传源码:#!/usr/bin/envnode//提交前检查是否有冲突,如果有冲突,process.exit(1)constexecSync=require('child_process').execSync//gitforallconflicts到处都会生成如下格式的信息,所以写一个正则constisConflictRegular="^<<<<<<<\\s|^======$|^>>>>>>>>\\s"letresultstry{//gitgrep命令将执行perl的正则模式来匹配所有满足冲突条件的文件results=execSync(`gitgrep-n-P"${isConflictRegular}"`,{encoding:'utf-8'})}catch(e){console.log('未发现冲突,等待提交')process.exit(0)}if(results){console.error('发现冲突,请在提交前解决,冲突文件:')console.error(results.trim())process.exit(1)}process.exit(0)将此文件复制到.git/hooks/pre-commit,然后执行chmod777pre-Commit可以在每次commit的时候检查之前的文件是否有冲突。有一个更好的方法吗?试想一下,我们在写hooks的时候,并不是一次就把代码写对了,所以需要经常把这个文件copy到.git/hooks目录下;有没有更好的办法?一些。只需在.git/hooks下创建一个shell脚本来调用这个js文件即可。#!/usr/bin/envnodeconstexecSync=require('child_process').execSyncexecSync("./pre-commit.js")shebang写法在使用git命令运行时没有问题,但是在UsingtheGit-SourceTree的GUI,会报node命令不存在,这是新版osx的安全策略导致的(可以运行whichnode命令看看和上面shebang的区别),使用在这种情况下,以下脚本完美运行。#!/usr/bin/envbash#支持sourcetreeexportPATH=/usr/local/bin:$PATHnode"./pre-commit.js"注意:注意node'./pre-commit.js'指的路径to如果你在当前项目的根目录下运行gitcommit,那么pre-commit.js是一个相对于当前根目录的路径。如果要优化,可以通过Git的一些默认环境变量进行配置。到这里基本就结束了,但是回想一下我们之前说过的“clienthooks不会被其他项目成员克隆”,所以需要一个策略来保证项目的每个成员都安装了这个hook。由于我们的前端项目需要每个成员通过npmstart命令来启动服务,所以我们可以在npmstart中做一些小技巧。constfs=require('fs');//判断pre-commit是否已经存在,如果不存在则读取pre-commit.sh并写入if(!fs.existsSync('.git/hooks/pre-commit')){if(!fs.existsSync('.git/hooks/')){fs.mkdirSync('.git/hooks/');}让preCommitFile=fs.readFileSync('./pre-commit.sh');fs.writeFileSync('.git/hooks/pre-commit',preCommitFile,{encoding:'utf8',mode:0o777});}总结:任何可以被JS改写的项目,最终都会被JSWrite改写。