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

综合编程 HaHack

需求描述

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

比如,在上一篇文章,我们自己定义了一个 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

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

安装钩子

服务端钩子

工具函数

稿源:HaHack (源链) | 关于 | 阅读提示

本站遵循[CC BY-NC-SA 4.0]。如您有版权、意见投诉等问题,请通过eMail联系我们处理。
酷辣虫 » 综合编程 » 化繁为简的企业级 Git 管理实战(五):使用钩子推进团队代码管理

喜欢 (0)or分享给?

专业 x 专注 x 聚合 x 分享 CC BY-NC-SA 4.0

使用声明 | 英豪名录