引言

最近参加了“前端规范制定topic”小组,小组成员一起制定了html、css、js、es6、vue和react等规范,但规范制定好了怎么进行推广去强制执行呢,已知我们的项目都是用git做管理的,所以马上想到在git上做文章,本文讲述的就是如何在git上推行代码强校验。

git知识点

说到git,我们先来了解下平时项目中不是很关注的几个git概念.

git仓库

git是分布式版本管理系统,可以有多个代码仓库,所有参与项目的开发者都可以拥有自己的本地仓库,每一个本地仓库都是一个完整的版本库,即使不联网,也可以任意的进行开发、创建分支、commit和查看版本的历史提交记录等。

但每个人都在自己的本地仓库开发,怎么做到代码共享和同步呢?在我们的项目中,通常都会建立一个大家都可以访问的共享仓库,这个共享仓库放在一个专门的线上服务器上,我们也叫它远程仓库。远程仓库和本地仓库的唯一差别就在于它是裸仓库,就是不包含任何工作目录,仅仅是由 “.git” 目录组成的。它作为服务器仓库供各开发者push、pull数据,实现数据共享和同步,不保存文件,只保存历史提交的版本信息等。

git存储方式

说完git仓库,我们来了解下git的存储方式。git存储数据更像是把数据看作是对小型文件系统的一组快照,每次提交更新或者是保存项目状态时,它主要对现有的文件制作一个快照并保存这个快照的索引。这个“快照”就是git对象,而“快照的索引”就是对象名。所有用来表示项目历史信息的文件,都是通过一个40字符的(40-digit)“对象名”来索引的。对象名看起来像这样的:26e5847434caa7597c4088de8ecab9cd567957d1。

在git里,每一个“对象名”都是对“对象”内容做 SHA-1哈希计算得来的, SHA-1是一种密码学的hash算法,这样在每个仓库中不同内容的对象就会有不同的对象名。git有四种类型的对象:"blob"、"tree"、 "commit" 和”tag”:

  • “blob”用来存储文件数据,没有文件名,只有内容
  • “tree”有一串指向blob对象或是其它tree对象的指针,它一般用来表示内容之间的目录层次关系
  • “commit” 指向一个"tree对象", 并且带有相关的描述信息,如提交者、提交时间、注释等等
  • “tag”用来标记某一个提交(commit) 的方法

所以下面所描述的获取文件信息基本上都是通过各种git命令操作hash对象名来获取的,这也是为什么在这里介绍“git存储方式”的原因,方便大家更深刻的了解git命令。

作用域

由git仓库的定义可以看出,本地仓库因为是本地的,任何能接触得到仓库的人都可以进行修改、删除等,所以本地仓库不适合做代码强校验。那只能考虑远程仓库了,可以当用户push推送的时候,校验代码,如果不符合规范,就拒绝这次提交,虽然你不能阻止开发者写出糟糕的代码,但可以防止这些代码流入官方的代码库。

git钩子

好了,确定了规范在服务端仓库上来强推行,但怎么做到当用户push动作触发的时候去做一下代码强校验呢,经过调研发现,git钩子正好解决了我们的这个问题。

什么是git钩子呢?git钩子是在git仓库中特定重要动作发生时自动运行的脚本,它可以让你自定义git内部的行为,在开发周期中的关键点触发自定义的行为。这样来说,git钩子就可以帮我们来推行规范了。

git钩子到底什么样呢,它存在于每个git仓库的.git/hooks目录中,当你观察.git/hooks时,你会看到下面这样的文件:

hooks目录下展示的钩子并不全,这里带simple后缀的只是git的大部分钩子,.sample拓展名防止它们默认被执行,想要运行一个钩子,去掉后缀名或者在git官网查看相应钩子名称添加新文件即可。

  • 钩子分类

    按照钩子的定义,hooks下的钩子可分为本地钩子和服务端钩子两类。本地钩子基本由提交和合并这样的操作所调用,而服务器端钩子主要用于接收推送这样的联网操作。上面“作用域”部分已经提到,我们只能在服务端仓库做代码强校验,所以接下来主要研究服务端钩子。

  • 钩子语言

    这些钩子就是git内置的一些脚本,内置的脚本大多是shell和perl语言的,但你可以使用任何脚本语言,只要它们最后能编译到可执行文件。本人对python比较熟,所以整个的开发用的是python语言。

git服务端钩子

由上面的git知识点一步步看下来,我们就可以确定了代码校验合适的地方是在服务端钩子上,但服务端钩子也有好多,我们的代码规范要在哪个钩子做比较合适呢,接来下就具体介绍下服务端最有用的3个钩子,并找出一个适合我们的钩子。

  • pre-receive

这个脚本在git push向远程仓库推送操作时,最先被调用。它没有参数,但是可以从标准输入获取一系列的推送引用。如果它以非零值退出,所有的推送内容都不会被接受,所以这是强制推行开发规范的好地方。

#!/usr/bin/python
# -*- coding: utf-8 -*- import re,fileinput for file_line in fileinput.input():
#从标准输入可以获取三个值
#推送前的引用指向的内容的SHA-1值,用户准备推送的内容的SHA-1值,引用的名字(分支)
old_hash,new_hash,branch = re.split(r'\s+', file_line.strip('\n'))
# 放弃推送
# sys.exit(1)
  • update

update脚本和pre-receive脚本十分类似,不同之处在于它会为每一个准备更新的分支各运行一次。假如推送者同时向多个分支推送内容,pre-receive只运行一次,相比之下update则会为每一个被推送的分支各运行一次。它不会从标准输入读取内容,而是会接受三个参数,这三个参数信息和pre-receive在标准输入读取信息相同。如果update脚本以非零值退出,只有相应的那一个引用会被拒绝;其余的依然会被更新。

#!/usr/bin/python
# -*- coding: utf-8 -*- import sys
#接受三个参数
#引用的名字(分支), 推送前的引用指向的内容的SHA-1值,用户准备推送的内容的SHA-1值
branch,old_hash,new_hash = sys.argv
# 只放弃当前分支的推送
# sys.exit(1)
  • post-receive

post-receive脚本在成功推送后被调用,可以用来更新其他系统服务或者通知用户,它接受与 pre-receive相同的标准输入数据。它的用途包括给某个邮件列表发信,通知持续集成(continous integration)的服务器,或者更新问题追踪系统(ticket-tracking system)等。

服务端推送成功后调用的钩子不止post-receive这一个,如上面.git/hooks图中的post-update也是其中之一,但是为什么不介绍post-update呢?原因是它的输入获取值太单一,post-receive更像是post-update的超级集合,所以推送成功后的调用我们一般用post-receive。

我们经常用到的gitlab中的web hook就绑定了这个钩子,当然web hook是绑定了好几个不同的钩子的,post-receive只是其中一个,如下图的web hook的中的Push events事件触发的就是.git/hooks中的post-receive脚本

分析这三个钩子,我们显然选push成功前调用的钩子,那到底是选pre-receive还是update呢?考虑到我们的项目很少有一次push多个分支的场景,最终选了pre-receive钩子来做我们的代码强校验。

在pre-receive钩子里做代码校验

钩子选择好了,接下来就是怎么做了,下面是一个简单的流程图,具体为从标准输入中获取三个值,分别是推送前的引用指向内容的SHA-1值,用户准备推送内容的SHA-1值和分支名,我再代码里分别用变量old_hash,new_hash和branch来表示这三个值,下面有用到。根据这三个值用git命令分别获取用户信息和提交的增量文件,把这些文件推送到eslint服务上进行代码校验,校验成功就直接push通过;不成功则在客户端返回校验结果,push不通过。

根据上面的描述,重点介绍下怎么获取用户信息和增量文件

  • 用户信息

获取用户信息的目的是传给eslint服务端,在服务端可以给分析用户的行为及给用户发送邮件等 这个命令可以定制化格式只获取用户的信息

  • %cn: committer name
  • %ce: committer email
  • %ct: committer date, UNIX timestamp
  • --no-patch: 不显示提交差异
'git show --format="%%cn %%ce %%ct" --no-patch %s' % new_hash

定制化后运行的结果是下面这样的,可以获取提交者的信息:

  • 增量文件

增量文件取得是本次推送引用指向内容的SHA-1值和推送前的引用指向内容的SHA-1值中间的差值。命令如下,其中 --name-status是只取差异文件的名字和状态值

为什么不直接取本次推送引用指向内容的SHA-1值而取差值呢,原因是上次推送和本次推送中间可能隔了好几个commit,每一个commit对象都会生成一个唯一的SHA-1哈希字串的。

'git diff --name-status %s %s' %(old_hash,new_hash)

运行后得到的结果是:

后面的就是怎么获取文件及和eslint服务通讯的问题了,在这里不是重点就略过了...

总结

本文可以说是我接到任务后,从只了解git的git pull、git clone、git push等几个常用命令到怎么在git上实现我们的需求的一个探索过程,希望里面的介绍对不是很熟悉git的同学有点帮助,另外也简单介绍了下我们强推规范的大致流程。后续会继续研究下gitlab和git钩子的关联关系。

在Git上如何强推代码规范的更多相关文章

  1. git上传自己的代码

    感谢这个哥们的博客,不过里面有些错误. http://www.cnblogs.com/ruofengzhishang/p/3842587.html 下面是我自己的实践成功的: 这篇文章写得是windo ...

  2. 更加方便的使用git上传自己的代码

    经过以上的培训,同学们肯定对git的基本使用没有什么问题了.但是每次代码有更改后,依旧需要 git  add  * git  commit * git   打开vim编辑器,编辑提交信息 或者 git ...

  3. 使用Git上传本地项目代码到github

    前提:(1)ssh密钥(让本地与git链接) &  (2)装好gitbash 1.git中创建好库 2.文件夹中输入:git init (出现隐藏的.git文件) 3.git remote a ...

  4. 从git上pull下的代码,执行时提示:ModuleNotFoundError: No module named '......',解决方法如下:

    方法一: 如果没有安装,如下: 1.PyCharm : file-> setting->Project interpreter–>package2.右侧有个+ 点击3.进入后 搜索p ...

  5. Git 如何优雅地回退代码

    前言 从接触编程就开始使用 Git 进行代码管理,先是自己玩 Github,又在工作中使用 Gitlab,虽然使用时间挺长,可是也只进行一些常用操作,如推拉代码.提交.合并等,更复杂的操作没有使用过, ...

  6. laravel代码规范强制检查

    目录 介绍 代码规范检查与修复 在git commit时自动检查代码规范 后记 介绍 在团队协作开发中,代码规范是必要的.以前的规范都是自己定,然后手动检查,很难做到有效的约束. 现代的PHP,则有得 ...

  7. CODING DevOps 代码质量实战系列第一课:代码规范与 Git Flow

    讲师介绍 杨周 CODING DevOps 架构师 CODING 布道师 连续创业者.DIY/Linux 玩家.知乎小 V,曾在创新工场.百度担任后端开发.十余年一线研发和带队经验,经历了 ToB.T ...

  8. JAE京东云引擎Git上传管理代码教程和京东云数据库导入导出管理

    文章目录 Git管理准备工作 Git工具上传代码 发布代码装程序 mywebsql管理 京东云引擎小结   JAE京东云引擎是京东推出的支持Java.Ruby.Python.PHP.Node.js多语 ...

  9. git 从远程拉取代码、推代码的步骤

    (注:如果是几个人共同管理项目,并且你的队友在你之前推过代码,那你就需要 git pull 一下,把代码拉到本地,解决一下冲突,再执行以下步骤,将本地代码推到远程仓库.) 第一步:查看当前的git仓库 ...

随机推荐

  1. 201521123109《java程序设计》第三周学习总结

    1. 本周学习总结 初学面向对象,会学习到很多碎片化的概念与知识.尝试学会使用思维导图将这些碎片化的概念.知识组织起来.请使用纸笔或者下面的工具画出本周学习到的知识点.截图或者拍照上传. 2. 书面作 ...

  2. 201521123006 《Java程序设计》第1周学习总结

    1. 本章学习总结 (1)java在使用的过程中可以发现其本身有着许多为了节约资源而作的设计,而java根据其应用领域分为了三大平台:Java SE.Java ME与Java EE.在本周的学习中我们 ...

  3. ops-web运维平台data.jsp-jquery-mootools

    data.jsp页面, 下面列出的是 <body>部分 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang=& ...

  4. jquery-post get 同步问题

    解决方法1: 在全局设置: $.ajaxSetup({ async : false }); 然后再使用get.post请求 $.get("register/RegisterState&quo ...

  5. git记录用户名

    windows下比较比较好用的Git客户端有2种: 1. msysgit + TortoiseGit(乌龟git) 2. GitHub for Windows github的windows版也用过一段 ...

  6. MySql Jar 包下载

    MySql JAR 包下载 我们要使用Spring 链接MySql  需要两个Jar 包   一个是C3p0   一个是MySql 的Connection Jar  包 C3p0: 进入下面的网址 h ...

  7. (转)Unity3D中移动物体位置的几种方法

    1. 简介 在unity3d中,有多种方式可以改变物体的坐标,实现移动的目的,其本质是每帧修改物体的position. 2. 通过Transform组件移动物体 Transform 组件用于描述物体在 ...

  8. 移动WEB 响应式设计 @media总结

    第一种: 在引用样式的时候添加 <link rel="stylesheet" media="mediatype and|not|only (media featur ...

  9. 冒泡排序(Bubble Sort)

    冒泡排序的基本思路 冒泡排序是一种效率极低的排序,首先它需要知道数组的有效数据长度,再对数据第一个和第二个两两比较,按照比较规则进行交换,然后第二个数据和第三个数据进行比较,按照比较规则进行交换:第一 ...

  10. javascript特效300例----抄书喽

    -javascript300例- #body_div { background-color: #202425; color: white; margin: 0 auto; border: 5px gr ...