对于每个开发者来讲,git 仓库是我们几乎每天都要接触的东西,但是实际上大多数的 git 仓库管理都是非常随性且不规范的,在某些情况下这样做并没有太大的问题,但是当协作成员逐渐增多、仓库职责逐步扩展时,很多原本不规范的小问题会被逐渐放大乃至产生一些极为严重的问题。笔者所在的飞冰(ICE)团队在 2018 年 2 月开源了 alibaba/ice
这个仓库,经过不到一年的时间终于在 2018 年末达到了 1w+ stars 的里程碑,在管理这个仓库以及运营社区的过程中我们积累了一些或大或小的最佳实践,希望能分享出来帮助到其他开源或者没开源的 git 仓库管理者。注:对于 git 的操作,笔者自知还处于一个比较初级的阶段,如有错误的地方还望指出。
合理的拆分仓库
当我们说管理仓库的时候,其实面向的不是一个单一的仓库,而是一个产品、一个项目甚至一个业务,这背后可能会有多个仓库也可能只有一个仓库,因此在前期的规划上要尽量梳理清楚,核心避免两个误区:
误区 1:每个职责都建一个仓库
这个方案可能是多数人的直觉反应,这种方式会让产品对应的仓库数快速增多,导致长期管理成本陡增:
- 仓库权限管理成本高且容易混乱
- 代码开发提交成本高
- issue/PR 太过零散,难以统计管理
- ……
实际上,飞冰(ICE)原先在内部的时候,我们开发了很多业务组件,每个业务组件都是一个单独仓库,然后最近在做统一升级(工具、规范或者其他变更导致)的时候给笔者个人带来非常大的困扰:
- 有的组件(仓库)已经不再维护但没有任何标记
- group 权限管理太过松散导致出现一些跟官方无关的组件
- 升级过程中需要频繁切换仓库操作
因此,我们需要避免过于零散的管理方式,然后结合实际场景做适当的聚合。
误区 2:所有的职责都用一个仓库承载
在前端社区里,随着 lerna 这个批量发布包工具的出现,这种方式越来越流行,一些非常热门的项目比如 babel、React、jest 等都逐渐迁移到这个方案。先抛开 lerna 这个工具提供的能力,这种聚合式的管理方式给仓库管理者节省了很多成本,比如:
- 只需要管理一个仓库
- issue/PR/wiki 等都收敛到一个地方管理
但是在实践这种方式的时候有可能会走偏,还是以笔者所在的 ICE 团队做反面教材,踩了误区 1 的坑之后,在做开源版本的时候我们过段把所有包都放到同一个仓库,然后通过目录结构来保证职责清晰,这个方式也同样如上面所提到的给我们的管理带来了诸多便利,但在经历了一年的迭代之后目前也遇到了一些问题:
- 职责多代表代码多,然后随着历史记录的增长,仓库 clone 速度一日不如一日,尤其在一些小公司的慢速网路环境下(即便加了 --depth)
- 目录结构相对复杂,对有心贡献代码的社区同学不够友好
因此我们推荐「在方案 2 的基础上按照职责再做一层拆分」,结合 alibaba/ice
这个仓库,我们后续会把 React 物料代码、Vue 物料代码、Angular 物料代码分别拆出去成为三个独立仓库,一方面降低主仓库的体积,另一方面Vue 的贡献者不需要关心其他对他没有意义的文件目录。
建立团队内的操作规范
笔者曾经有幸参与过淘宝前端团队的代码规范制定以及相关工具落地,因此深知规范之于团队的重要性,同时也有一些制定规范的原则:(1) 规范首先保证正确,其次提升质量;(2) 规范不能过多影响到效率(两者的权衡需要结合实际场景)。以下就是我们目前在遵循的一些规范:
保护分支
根据仓库情况设定保护分支,禁止直接往保护分支提交代码,在非常特殊的情况下 admin 账户可以绕过。
新建分支规则
- 分支名称需要有语义,比如 ice-scripts/fix-foo-bug
- 如果需求比较简单,时间周期比较短,那么直接从 master 切一个分支,然后通过 PR 合并后到 master,合并之后发布对应包的版本
- 如果需求包含多个变更点,比如 Iceworks 发布版本,往往涉及到多个功能点,开发周期一般会在一周左右,如果每个 PR 都往 master 上合并,很难把控整体的进度。因此我们有以下约定:
- 先从 master 切出 release 分支(如 release/iceworks-2.16.0),然后提一个基准 PR,PR 中需要补充当前版本包含的功能列表以及发布先后顺序等,该 PR 主要用于管理此次版本开发进度,代码无需 review,release 分支不允许直接推送代码
- 然后每个功能变更都从 release 分支切出新分支,同时 PR 也需要合并到对应 release 分支,切出的分支不需要包含版本信息(比如 iceworks/fix-xxxx 即可)
- 等所有 PR Review 完成并且合并到 release 分支之后,在 release 分支进行发布,发布完成后再将 release -> master 的 PR 合并(此处不在 master 分支发布的原因是担心发布时可能会出各种问题,需要再次做代码变更)
commit message 规范
好的 commit message 可以让人快速了解代码意图,加速 review 进程,未来对于整个代码仓库的历史追溯也会更加方便,关于这一点社区有足够多的规范可以参考,此处不再一一赘述,有兴趣可以参考末尾的参考链接。
PR 合并流程
github 默认提供了三种合并 PR 的方式,关于三种方式的区别可以参考文末的相关链接,我们认为大多数情况应该选择 Squash and merge,因为 squash 会将当前 PR 的多个 commit 合并,让整个提交历史更加干净清晰,但是在将上文提到的 release 分支合并到 master 时,是否应该将每个功能点的 commit 合并成一个 release commit,目前我们还没有思考清楚,希望能得到一些建议或者指导。同时在合并 PR 的时候 Reviewer 有责任重新编写 commit message 以保证语义更加准确。
这里简单追溯一点历史:在最早期的时候,github 还没有提供 squash merge 的方式,当我们向开源仓库提交一个 PR 时,在仓库作者 review 完成之后一般会要求提交者将 commit 合并,因此很多人都有谷歌过「如何合并 commit」这样的关键词,而如今只需要点一下按钮即可,这也是工具对效率提升的一个体现。
发布流程
对于管理工具包的同学,都应该熟悉并且遵循 Semver 规范(语义化版本),这是原则,在此基础上需要遵循以下规范:
- 测试版本:版本号需要遵循 x.y.z-n 的规则,通过
npm publish --tag beta
发布,很多同学包含笔者本人经常会忘记--tag beta
,不知道有没有更加有效的方式约束? - 正式版直接通过
npm publish
发布,发布之后执行tnpm sync
同步内部版本 - 正式版本发布之后,需要同时创建对应的 git tag,tag 命名规则:产品名/x.y.z,比如
ice-scripts/1.0.2
其他不重要的事情
如何保证规范落地
结合曾经在淘宝前端团队推动的规范落地以及当下在 ICE 团队制定的规范,两点结论可供参考:
- 规范需要保证多数人认可,然后由松到紧逐步迭代,人跟着规范逐步成长
- 小团队靠素养,大团队靠工具:在小团队内制定规范,需要做的就是反复强调,逐渐让每个人形成习惯;而在大团队里显然是没法关注到每个人的,此时需要借助工具,比如 eslint,commit-check 以及像门神这种强流程的工具
如何迭代历史版本
上文说的一些工具包的发版,假设我有一个工具包 ice-scripts 在 1.6.5 的基础发布了一个 break change 的版本 2.0.0,正常情况下我们肯定是在 master 分支(2.0.0 的代码)的基础上逐步迭代,但 1.x 的版本可能还有用户使用,当我们需要修复 1.x 的一个 bug 时如何去做?这里推荐一个流程:
- 首先基于 git tag
ice-scripts/1.6.5
切出一个stable/ice-scripts-1.x
的分支(幸亏之前打了 tag,否则要找到对应的 commit 还是有点工作量的) - 将
stable/ice-scripts-1.x
设为保护分支,可以理解为 1.x 版本的 master 分支 - 从
stable/ice-scripts-1.x
切出新分支ice-scripts-1.x/fix-bar
,然后修改代码提交 PR 到stable/ice-scripts-1.x
分支上 - Review 完成后合并代码,然后在
stable/ice-scripts-1.x
分支上进行发布
如何做好答疑
运营社区的过程一定需要频繁面对用户的疑问,如何在满足用户的同时又能保证自身投入不影响到正常工具显得极为重要了,对于技术产品,根据面向用户群体的不同目前两种主流答疑方式:
- github issue: 纯异步交流,保证所有问题讨论都能沉淀下来,同时因为异步沟通有成本,大家会努力一点表达清楚自己的意图,相对来讲沟通质量更高,但响应速度之类的无法保证
- 类钉钉群:同步交流,响应速度快,但是对于维护者来说时间容易被打碎,降低工作效率
答疑这块目前整体上还是占用了太多时间,这块也一直处于探索阶段:
- 做好产品以及文档的积累
- 钉钉群答疑进行值班机制,每个人负责一天,每个人需要对产品的全貌正确了解更多:事实上会有点难
- 钉钉机器人问题沉淀
- 引入外包机制
如何管理 issue
ICE 目前整体的 issue 管理做的不好,笔者也是近期开始治理这块,一些建议仅供参考:
- 通过 issue 模板努力提升 issue 质量:ICE 仓库里早期的 issue 质量非常低,很多问题都无法复现
- 基于产品分类建议对应的标签分类,每个 issue 关联标签,然后由对应负责人统一处理
- issue 不要求及时处理,但鼓励能通过沟通或其他方式快速明确问题,防止时间长了不理解 issue 的描述然后又无法跟 issue 作者沟通
如何运营社区
ICE 团队目前维护着 5 个钉钉答疑群(每个 1000 人)以及技术论坛的官方帐号,但整体活跃度都比较一般,目前无论是精力上的投入还是运营产品的经验都比较缺失,希望能得到一些建议或者支持。
有趣的机器人
github 上有很多方便的机器人(or App?),这里推荐个人觉得比较有用的两个机器人:
- delete-merged-branch:合并 PR 之后会自动删除对应分支,防止无用分支的堆积
- Weekly Digest:每周创建一个 issue,汇总仓库一周内的动态,比如:新增了哪些 issue/PR,有哪些人 star 了仓库等,示例 Weekly Digest (30 December, 2018 - 6 January, 2019)
其他有趣的机器人欢迎推荐。