引言

最近参加了“前端规范制定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. Java中如何引入结对编程

    引自微信: 很多同学说: 我程序写得好,ACM比赛能得分, 就好了,软件工程讲的那些有用么? 有些学校的 <软件工程>课,由于要求太简单,反而不能说明软件工程的价值. 其实好办, 让学生结 ...

  2. PowerShell脚本—停止占用8080端口的进程

    $str = netstat -ano $list = $str.Split('\n') ; $i -lt $list.Length; $i++) { $item_list = [System.Tex ...

  3. 【转】MySQL分库分表环境下全局ID生成方案

    转载一篇博客,里面有很多的知识和思想值得我们去思考. —————————————————————————————————————————————————————————————————————— 在大 ...

  4. bzoj 3212 Pku3468 A Simple Problem with Integers

    3212: Pku3468 A Simple Problem with Integers Time Limit: 1 Sec  Memory Limit: 128 MB Description You ...

  5. 修改yum源

    安装 centos 之后,修改 yum 源到其它国内源 1. 备份原文件 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Ba ...

  6. Lodop 动态加载模板,动态加载数据

    最近需要使用Lodop打印控件,所以就研究了一下,期间从网上找了诸多的东西,基本全是对HTML进行打印的,没有找到我想要的,就只好自己动手丰衣足食. 这篇文章主要讲述的是Lodop与数据的结合使用,官 ...

  7. P1035

    P1035 时间限制: 1 Sec  内存限制: 128 MB提交: 87  解决: 36[提交][状态][讨论版] 题目描述 给出一张n*n(n< =100)的国际象棋棋盘,其中被删除了一些点 ...

  8. S2_OOP第一章

    面向对象设计的过程就是抽象的过程 步骤: 第一步:发现类 第二步:发现类的属性 第三步:发现类的方法 抽象是遵循的原则 属性和方法的设置是为了解决业务问题 关注主要属性和方法 如果没有必要,不增加额外 ...

  9. Ansible(一) - 入门及安装

    Ⅰ. Ansible简介 ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet.cfengine.chef.func.fabric)的优点,实现了批量系统配置 ...

  10. 常见SQL分页方式效率比较

    结一下. 1.创建测试环境,(插入100万条数据大概耗时5分钟). ,) ) )) ),end 2.几种典型的分页sql,下面例子是每页50条,198*50=9900,取第199页数据. id id ...