转载

化繁为简的企业级 Git 管理实战(五):使用钩子推进团队代码管理

需求描述

在团队开发中,保证团队维持一致的代码管理策略,避免在同样的问题上重复挖坑和踩坑,有时是一件非常困难的事情。

比如,在上一篇文章,我们自己定义了一个 modules.json 文件,用来定义每个子模块应该使用什么分支。但即使是这样一个简单的文件,在实际开发过程中都会闹出各种让人哭笑不得的奇葩笑话:

  • JSON 格式错误,最常见的比如多了或者少了一个逗号。于是 fmanager 在解析 modules.json 的时候就会因为格式错误而退出。
  • 键值重复。比如在 modules.json 里头已经定义了某个子模块的配置,但后面的人却没有仔细检查是否已经配置了该模块,又增加了一条对该模块的配置,导致只有最后一个配置才生效。
  • 拼写错误。比如将 master_dev 模块拼写成了 Master_dev 。

为了避免在这类低级的问题上重复踩坑,我们将钩子应用在开发的各个阶段中,在一些重要的动作发生时触发自定义脚本进行若干检查,并在完成若干动作后执行一些后续指令。这些钩子对推进团队代码管理起到了非常有效的作用。

下面我将

钩子的基础概念

Git 能在特定的重要动作发生时触发自定义脚本,要达到这个目的就是利用钩子。

如果按照钩子安装的位置来划分,钩子可以分为如下两种:

  • 本地钩子。安装在每位开发者的本地仓库中,并在本地被触发执行。这类钩子通常作用在客户端推送代码之前的阶段。前面提到的 pre-commit 就是一个客户端钩子。
  • 服务端钩子。安装在远程仓库中,并在接受客户端推送代码前后由服务端执行。这类钩子通常作用在服务端收到客户端的代码推送请求之后的阶段。

本地钩子

工具函数

# coding: utf-8 # author: panweizhou  importsys,os,io,subprocess,json,re  defgetSubmoduleNameAndPath(): '''获取子模块信息'''  root_path = getRootPath() ifroot_path !=None:  output = subprocess.Popen(['git submodule --quiet foreach --recursive /'echo $toplevel/$path/''], stdout=subprocess.PIPE, shell=True)  oc = output.communicate() #取出output中的字符串  submodule_dict = {} forelementinoc: ifelement !=None:  sb_list = element.split('/n') foreleminsb_list: if(elem !=""):  path = elem.strip()  name = path.replace(root_path+"/",'')  submodule_dict[name] = path returnsubmodule_dict else:  print(warning_color)  print(''' 警告:检测到当前工程不是 .git 工程,文件目录可能已经损坏! ''')  print(normal_color)  os.chdir(pwd) returnFalse  defgetRootPath(): ''' 找到工程根目录 '''  git_path = ".git"  pwd = os.getcwd() whileTrue: ifos.path.exists(os.path.join(pwd, git_path))andos.path.isdir(os.path.join(pwd, git_path)): returnos.path.abspath(pwd) else: if(os.path.exists(os.path.join(pwd,"../"))):  pwd = os.path.join(pwd, "../") else: returnNone   defgetModulePath(): ''' 找到当前模块的根目录  如果当前是主工程,则返回主工程的根目录'''  git_path = ".git"  pwd = os.getcwd() whileTrue: ifos.path.exists(os.path.join(pwd, git_path)): returnos.path.abspath(pwd) else: if(os.path.exists(os.path.join(pwd,"../"))):  pwd = os.path.join(pwd, "../") else: returnNone   defisRootProject(): ''' 判断当前是否处于主工程 '''  module_path = getModulePath()  git_path = ".git" ifos.path.isdir(git_path): returnTrue else: returnFalse   defaddress_comp(repo1, repo2): ''' 比较两个地址是否相同 '''  pos = repo1.find("://") ifpos >0:  repo1 = repo1[pos:]  pos = repo2.find("://") ifpos >0:  repo2 = repo2[pos:] returnrepo1 == repo2  defisRepo(repo_address): '''判断当前是否处于某个模块'''  output = subprocess.Popen(["git remote -v | grep 'fetch' | awk '{print $2}'"], stdout=subprocess.PIPE, shell=True)  oc = output.communicate()  repo = oc[0].strip() ifaddress_comp(repo, repo_address): returnTrue else: returnFalse 

举例一:JSON 格式解析

判断

远程钩子

本地钩子

打开任意一个本地 Git 仓库的 .git/hooks 目录,你会发现有一堆文件:

[-] YOUR_REPO/.git/hooks/  |- applypatch-msg.sample  |- commit-msg.sample  |- post-update.sample  |- pre-applypatch.sample  |- pre-commit.sample  |- pre-push.sample  |- pre-rebase.sample  |- prepare-commit-msg.sample  `- update.sample 

这些文件就是钩子的模板文件。每个模板文件的文件名

安装钩子

服务端钩子

工具函数

原文  http://hahack.com/work/enterprise-class-git-version-control-5/
正文到此结束
Loading...