欢迎来到爱学习爱分享,在这里,你会找到许多有趣的技术 : )

Git 工程化最佳实践

开发者头条 662℃

1. 本文导读

本文对应的 git-standardize 项目地址 https://github.com/vimerzhao/git-standardize

1.1. 问题背景

大部分程序员对于Git的理解还停留在

git add .
git commit -m "update"
git pull
git push

的阶段,但这在实际项目开发中是远远不够的。
举一个简单的例子,现在我们需要过滤所有修复bug的提交,该怎么做?显然是无法做到的,因为无法从commit信息获知。但是,如果我们在每次commit信息里面都注明提交的类型,是不是就可以通过过滤指定类型来达到目的了。
再举一个例子,如果我们的分支命名都是

master-01
master-02
feature-add_sd_card_permission
bugfix-id-342141
bugfix-authorize-error

这种格式,我们是不是很不方便去做 定位分支的负责人,过滤指定分支 等操作,更不用说视觉上的混乱所造成的困扰了。
再比如,笔者近来发现某个仓库有大量构建产生的中间文件,究其原因,发现是因为管理人员设置的.gitignore配置如下

....
/build
....

显然,这种写法无法忽略子模块的 build 目录。

基于以上三个例子,Git使用的工程化、标准化是十分必要的。
我们所谓的造轮子,亦不仅仅存在于编程中,日常工作中常有大量的重复工作,亦是一种轮子,本文即 希望规范化、流程化Git的使用 ,以期提高开发者的效率。
本文基于作者工作中的教训和思考积淀而成,虽曰“最佳”,但也只是现阶段我心中的最佳实践,仅供参考。

1.2. 阅读须知

Git的作者Linus也是Linux的作者,Git最初也是Linux内核开发者在使用,所以其本身的配置和使用也是充满了类Unix的味道,诸如别名、命令、配置文件等等,都是Unix/Linux开发者习以为常的东西,但对于客户端、大前端的开发者可能相对陌生,所以,继续阅读本文之前,希望你对以下知识至少是有了解的

  • 基本的Shell命令:alias/source/grep等

  • 终端的基本使用,如通过Tab键可以自动补全命令

  • 配置文件的使用,如Bash的.bashrc/.bash_profile, zsh 的.zshrc,Git 的.gitconfig,他们的原理都是相似的

2. 仓库创建

无论是Github还是工蜂,我们新建一个Git仓库后,往往会出现以下提示:

某种意义上,这幅图会带来很多误解,我们在创建一个Git仓库后还有很多事情要做,一开始,我们或许习惯于渐进式的改进,但我们应该意识到这种工作是可以 流程化、自动化 的,即不要等到发现问题再去解决,而应该一开始就建立有效、可复用的机制。

2.1. 信息配置

使用git config配置必须要的用户信息

反面案例:

腾讯内部每个员工有自己的英文名和tencent邮箱,但是部分开发人员未注意,导致诸如
name(中文名)
name@gmail.com
的信息进入了提交历史

2.2. gitignore

github-gitignore 提供了各类型项目的.gitignore模版,基本可以直接使用,如需定制,参考 Git – gitignore Documentation ,确保自己理解了语法规则。一般而言,本地的配置、编译生成的中间文件是需要在项目建立之初就添加.gitignore的。

2.3. 分支规范

只允许使用以下分支命名项目

  • master

    • 主分支,也是用于部署生产环境的分支,确保master分支稳定性,任何时间都不能直接修改代码

  • release

    • release为预上线分支,发布提测阶段,会以release分支代码为基准提测

    • 分支命名细则:release-version

    • 当有一组feature开发完成,首先会合并到master分支,进入提测时,会创建release分支

    • 如果测试过程中若存在bug需要修复,则直接由开发者在release分支修复并提交

    • 当测试完成,经过一个周期的灰度之后,合并release分支到master分支

    • release分支的最终状态是每个线上版本的归档镜像

  • hotfix

    • 线上出现紧急问题时,需要及时修复,以master分支为基线,创建hotfix分支,修复完成后,需要合并到master分支和处于待发布的release分支

    • 分支命名细则:hotfix-creator-description

  • feature

    • 开发新功能时,以master为基础创建feature分支

    • 分支命名细则:feature-creator-description

Warning

是否需要引入develop分支以维持master分支的稳定性(上述机制的不足之处)有待商榷,过于复杂也不是一件好事,保证 合入分支自身的质量 看起来是更好的解决方案

推荐一篇参考文章 A successful Git branching model » nvie.com

2.4. commit规范

参考 angular.js commit规范
针对客户端的每次提交限制格式如下

<type>(<scope>):<subject> # (1) (2) (3)
<BLANK LINE>
<body> (4)
<BLANK LINE>
<footer> (5)
  1. type:本次改动的类型

  • feat: 添加新特性

  • fix: 修复bug

  • docs: 仅仅修改了文档

  • style: 仅仅修改了空格、格式缩进等,不改变代码逻辑

  • refactor: 代码重构,没有加新功能或者修复bug

  • perf: 增加代码进行性能测试

  • test: 增加测试用例

  • chore: 改变构建流程、或者增加依赖库、工具等

  • scope:本次改动影响的范围,建议每个工程划分好自己的模块,方便填写

  • subject:本次改动的简要描述,一般写这个就够了

  • body:更详细的改动说明,一般不使用,因为不推荐这么大的改动

  • footer:描述下与之关联的 issue 或 break change,一般不使用

  • Note

    建议

    • 建议每次commit的粒度不要太大,方便CodeReview

    • fix类型的提交最好附带上bug链接之类的信息

    2.5. GitHook

    GitHook应该在仓库创建之后尽早设置,为了避免重复工作,笔者以及针对上文提到的信息配置、分支规范和commit规范等提供了 强制检查 的能力,引入方式如下

    cd ..
    git clone http://git.code.oa.com/vimerzhao/git-standardize.git
    cd -
    cp -R ../git-standardize/.githooks ./
    cd .githooks
    chmod +x *[^rule]
    cd ..
    git config core.hooksPath .githooks
    cd ..
    rm -rf git-standardize
    cd -

    如果管理员配置好了hook并完成了服务器端的push,那么对于其他开发者,只需要

    git pull --rebase
    git config core.hooksPath .githooks

    使用效果如下:

    非法分支命名

    非法commit信息

    3. 仓库使用

    3.1. gitconfig

    参考 Git – Git Configuration

    3.2. GitHook

    如上所述,使用者clone下仓库后应该配置本地GitHook,避免不小心提交脏信息

    git clone ****
    git config core.hooksPath .githooks

    3.3. 别名设置

    下文会专门论述为什么推荐你在命令行而不是GUI工具中使用Git,本章主要讲述如何使用别名。别名在类Unix系统中普遍存在,即将我们最常用的命令设置一个更短更容易记住的别名,以提高使用效率。

    oh-my-zsh

    zsh是一款类似于 GitBash 的终端软件,而 oh-my-zsh 则是基于 zsh 深度定制的版本,其git插件提供了一套别名,推荐使用,避免重复造轮子。
    文档位置:git-cheatsheet
    配置位置:git.plugin.zsh

    使用这套别名可以有以下好处

    • 省力省心,开源社区长期优化的配置大概率比我们自己折腾的更加科学和健壮

    • 通用性强,任何一个使用 oh-my-zsh 的用户和你的别名习惯都是一致的,便于交流

    GitBash

    如果开发环境是 Mac/Linux ,强烈推荐使用 oh-my-zsh,如果是 Windows,目前看来还是使用 GitBash 最佳,推荐将 git.plugin.zsh 的别名规则平移到 GitBash 下,这样也符合上文提到的通用性原则。移植方法很简单,如下

    # 大意如此,视具体情况可能需要稍作修改
    move path/to/oh-my-zsh/plugins/git/git.plugin.zsh ~/.git.plugin.zsh
    echo `source ~/.git.plugin.zsh >> .bash_profile`

    GitAlias

    GitBash 使用 Linux别名 时有一个不太友好的问题,就是不支持自动补全,对于像git checkout这样的命令,非常需要自动补全,否则很容易拼错分支名称。
    所以推荐配置 Git别名 ,为了提高通用性,Git别名同样推荐基于 oh-my-zsh 的别名规则进行移植,下面是一段 git.plugin.zsh 的Linux别名配置

    ...
    alias gbr='git branch --remote'
    alias gbs='git bisect'
    alias gbsb='git bisect bad'
    alias gbsg='git bisect good'
    ...

    很容易发现,每个别名均以g开头以区分其他命令,而 GitAlias 均以git开头,所以对应的Git别名配置可以是

    ...
    git config --global alias.br    'branch --remote'
    git config --global alias.bs    'bisect'
    git config --global alias.bsb   'bisect bad'
    git config --global alias.bsg   'bisect good'
    ...

    如此一来,git branch –remote这个命令在 Mac/Windows/Linux 均可以通过gbr或者git br访问到。

    Note

    Linux别名:通过bash命令alias设置。

    Git别名:通过git config –global alias设置。

    Note

    如何移植 git.plugin.zsh?一行一行的修改alias语法为git config alias语法吗?笔者的解决方法

    # 提取所有关于别名的配置,并暂存
    grep -E "alias g[a-zA-Z]+=.*" path/to/git.plugin.zsh > temp1.sh
    # 改成GitAlias风格的别名
    sed "s/^alias g/git config --global alias./g" temp1.sh > temp2.sh
    # 去掉命令里面的 `git`,符合 GitAlias 语法
    sed "s/git //g" temp2.sh > git.alias.config.sh
    # 进行配置,运行后会注册到 .gitconfig
    source git.alias.config.sh
    # 删除中间文件
    rm temp*

    3.4. 命令封装

    所有的辅助命令均以gs_开头,这样的好处是可以利用Tab键的补全机制自动选择命令,避免冗长难记的输入

    gs_clear_local_barnch

    清理本地存在但是服务器端不存在的分支

    gs_branch_last_commit

    查看分支最后提交人和存活周期,辅助删除过期分支

    gs_past_commit_statistic

    统计过去一段时间内的代码提交数量,参数

    • $1 : 时间段或者起始时间,如7.days、2019-10-10

    4. 总结

    以上是笔者近期的思考总结,后面有新的想法和实践都会在此更新,欢迎关注 git-standardize。另外推荐阅读:Git内部原理剖析

    往期推荐

    修改遗留代码的艺术

    Git内部原理剖析

    Flutter:移动端跨平台技术演进之路

    点我查看原文,阅读体验更佳。

    转载请注明:爱学习爱分享 » Git 工程化最佳实践

    喜欢 (0)or分享 (0)