软件工程实践之 Git 开发流

软件工程实践之 Git 开发流

软件工程实践系列文章, 会着重讲述实际的工程项目中是如何协做开发软件的。 本文主要介绍如何使用 Git 来支撑整个开发流。html

outline

本文包括如下内容:git

  • operation: 团队保持一致的操做github

    • commit: 提交原子性的代码
    • history: 保持线性干净的历史
    • release: 遵循科学的发布规范
  • tool chain: 搭建自洽的工具链web

    • gitlab/github: 使用现代的开发平台
    • ci/cd: 让系统把控代码质量
    • sentry/k8s: 用版本链接整个系统
  • conclusiondocker

operation: 团队保持一致的操做

Git 提供了一套自由而又强大的 api, 咱们能够经过它以各类姿式来完成代码协做。 但俗话说得好, 选择越多人越懵。并无这句俗话 因此在团队协做时, 保持一致的操做是很重要的。api

commit: 提交原子性的代码

Git 的最小单元就是一个 commit。 咱们团队遵循的最佳规范是保持每一个 commit 的原子性: 一个 commit 只作一件事情。markdown

好比一个关于缺陷修复的 commit 能够很是简单, 它只有两行: 一行修复了代码逻辑, 一行加了单元测试。框架

另外一个关于重构的 commit 可能会修改 200+ 个文件, 但也由于只作了一件事情, 因此不会给 code review 带来很大负担。工具

img

原子性的 commit 不只能很好地支持 revert/cherry-pick/bisect 等一系列 Git 的原生命令, 并且在保持线性干净的历史这一点上, 也是相当重要的。oop

history: 保持线性干净的历史

随着时间的推移, Git 的每个 commit 会成长为一个枝叶繁茂的历史树。 基于 fast forward 的合并能让 Git 的历史树保持干净与线性。

img

这是咱们项目 git log 翻到四个月之前的一张截图, 能够看到历史依旧是线性干净的。

线性的历史意味着在每一个人提交代码前须要 rebase。 一个例外是在发布分支(master)上提交 hotfix 后, 合并回开发分支(dev)须要视状况关闭 fast forward (–no-ff)。 并且要求你们 rebase 则对团队成员的 Git 水平以及合并习惯提出了必定要求。

干净的历史则须要你们都严格遵循 commit 的原子性, 以及要按照标准撰写 commit message。 关于 commit message 的撰写, 阮老师有一篇《commit message 编写指南》讲的够好。 咱们也能够在 git hook 中开启对 commit message 的校验, 以确保格式的整洁统一。

经过fast forward merge + 统一的 commit message, 咱们就能维护一个不断成长、但又干净线性的历史树, 能最大程度地给各类 git 的版本操做提供便利。

release: 遵循科学的发布规范

咱们使用 git tag 来做为版本发布的标志。

img

由于咱们的项目是一个 web 服务端项目, 咱们同一时刻基本上只须要维护最新的版本, 因此咱们使用了日期型的版本号数字(v2019.9.9)。 在大部分开源工具里, 都会使用语义化的版本号(semver: v2.0.0)

基于原子的 commit、线性的历史, 在每次版本发布时, 咱们都会自动化地生成 tag/changelog。

img

一个遵循了良好规范的 tag 能最大程度地利用工具链的集成功能, 给开发、测试、上线、监控提供完备的功能。

tool chain: 搭建自洽的工具链

在注重团队协做、开发流程、发布质量的软件工程中, 会有一系列开发工具围绕 Git 的代码历史树, 提供了自洽的工具链。

gitlab/github: 使用现代的开发平台

咱们使用 GitLab 来管理代码项目, 其中重度使用的是 Merge Request 来做为 code review 的载体。 不过咱们跟着 GitHub 的设定,管它叫 PR (Pull Request)

为了维持 PR 的原子性, 大部分状况咱们遵循单个 commit 对应单个 PR, 这样既方便 review 也方便分支管理。 不过这样的开发流会产生很是多的 PR, 须要团队开发者都保持在一个更积极的开发状态下。

现代的开发平台还会集成更多工做流上的功能, 咱们还重度使用的是把 GitLab Runner 做为咱们 ci/cd 的工具载体。

ci/cd: 让系统把控代码质量

img

在提完 PR 之后, 系统会自动化地启用一系列的 Python/Django 检查。

img

经过 git tag 发布版本后, 系统会自动化地跑构建、灰度等一系列部署任务。

除了 GitLab Runner, 其它像 Jenkins/Travis CI/GitHub Actions 也能够相似的 ci/cd 功能。

集成 ci/cd 能让整个开发流变得更加柔顺, 让每个改动的影响均可以即时地经过数据展现出来。 ci/cd 加上 code review, 能最大程度地让代码库保持活性, 长远地能避免“往屎山上堆屎”的发生。

前面提到咱们的 PR/release 频率都会比较高, 因此 ci/cd 也须要在更短的时间内跑完, 以免龟速检测致使的各类心态爆炸、skip ci。 目前咱们项目平均能在 5min 内跑完包括 96% 覆盖率的单元测试的多项检查, 也能在 5min 内跑完从构建、灰度到全量的整个发布流程。

整个 ci/cd 的流程其实也跟写接口这样的业务相似, 是须要不断迭代、不断优化、不断适应更好的开发流的。

sentry/k8s: 用版本链接整个系统

在开发的流程走完之后, 软件工程还关心发布的流程、质量把控的流程。

咱们绑定了 docker image tag 与 git tag, 最终发布部署在 k8s 上的每个版本也跟 git tag 的版本强关联。 这样的设定之下, 好比像 kubectl rollout 的一系列操做就会跟 Git 历史树关联上。

img

> 咱们也使用了 sentry 来检测管理代码的线上问题。

全部的外部系统都使用着统一的 tag version 来关联问题, 这样咱们就给 debug, 历史溯源,分锅都提供了统一的工程语言。

conclusion

基于 Git 的开发流不是一个一成不变的框架, 它会由于项目特质、团队成员习惯、工具链的不同而有着不一样的表现形式。

咱们团队在软件工程的实践中, 保持并维护着这么一套开发标准:

  • 保持 commit 的原子性,一个 commit 只作一件事情。
  • 遵循编写 commit message 的标准,而且会在 code review 时关注。
  • 统一团队成员的操做习惯,使用 rebase + fast forward merge。
  • 自动化地生成 git tag 以及 changelog,并基于此作代码发布。
  • 搭建快速全面的 ci/cd 流程,自动化地作掉全部代码检查。
  • 使开发流与社区最佳实践一致,了解并利用好各种工具的集成功能。

这套开发流也给咱们提出了这些挑战:

  • 要对 Git 有必定了解,包括历史树操做等进阶知识。
  • 除了编码时,在协做时也要保持积极的态度,以及协做上的高标准。
  • 最重要的,对最佳实践的追求,以及不懂就学的态度。

这样的 Git 开发流,最终带来了这些效果:

  • 线性的历史让 debug、追溯变动、了解项目发展过程都变得很是友好。
  • 项目一方面能保持快速活跃的开发效率,另外一方面能保证长期维护的质量。
  • 最佳实践的讨论以及迭代,让团队内部一直维持着很好的工程师文化。

软件工程的实践中, 好的 Git 开发流是不可或缺的一部分。 之后咱们再以不一样的视角来分享更多软件工程的实践。

(完)


原文连接

相关文章
相关标签/搜索