Git 开发规范
糟糕的 SVN 仓库
之前的 SVN 仓库听说是接手的上家公司的原因才保留至今的,如今在甲方要求全面推行 Git 仓库和 DevOps 平台的浪潮下,终于我们要开始使用 Git 开发了。
其实在 SVN 的日子里,刚开始接触的时候确实有点痛啊,因为 SVN 目录在设计的的时候就模仿了 Git 多分支的结构,这里其实我一直就有个问题,我接触的两家公司都是用过 SVN 的,但是从来不会出现使用分支的用法,尽管 SVN 是支持分支的,所以这让我一度认为 SVN 不支持分支。因此我们为了实现 Git 的效果,就把 dev、ver、prd 创造了三个不同的目录,但是文件夹之间没有任何联系,仅仅是代码的三份存档,每次开发完毕合并的时候需要使用 BCopmare 工具对比合并到上一层文件夹中,所以每次开发上线简直是地狱体验。
其实 SVN 个人看来如果公司没有私有云盘或者公共文件服务器的话,也是一个存储文件库的替代方法,如果是协作开发,Git 的分布式多分支更适合团队协作。
当我们决定迁移到 Git 仓库的时候,我自然是义不容辞,结合自己之前公司和自己使用的经验在新公司发扬光大,现在想想当时确实是激情澎湃,一天就整出了一份我们自己使用的 Git 开发规约,因为确实项目太多了,自己能力再大也不会说一个人就把整个仓库都给迁移了,况且很多项目自己没有接触了解过,所以这份规约里面包含了分支开发的定义、迁移步骤、工作场景等部分,足够当时我们团队平时开发使用了。
Git分支开发规约
Git分支含义
- master/main(线上分支)
- 一个项目只能有一个master分支
- master分支并不是一个特殊的分支,它和其他分支完全没有区别,只是默认创建后大多数人懒得去改动它。
- master分支上的代码应该和线上代码始终保持一致
- master分支应该是保护分支,不可直接push,更不允许被删除
- 每次上线后都需要添加tag,建议用 上线日期 命名,用于存档和回滚
- develop(开发分支)
- 一个项目只能有一个develop分支
- 基于master分支创建,作为主开发分支,保存当前最新开发成果的稳定分支
- 为保证分支稳定可用,建议只能合并测试后可运行的的稳定分支,不允许直接在该分支做功能开发
- feature/topic(功能分支)
- 作为新功能或新特性开发分支,是我们最经常交互的分支
- 命名建议使用姓名和功能介绍组成,见名知意,知道是谁负责开发和大致开发内容,如 feature/sbc_addMqTranfer
- feature分支属于临时分支,可以只存在于本地仓库,功能完成并合并之后可选删除
- release(预上线分支)
- release分支主要用于上线前的各种测试和部署,需要基于本次上线将所有功能整合
- 命名建议根据上线日期决定,如 release/20230413
- release分支属于临时分支,上线后master标记tag后可选删除
- bugfix/hotfix(线上bug紧急修复分支)
- 如果是紧急问题,以master分支为基线,修复后直接部署。当问题修复完成后,需要和并到master和develop分支
- 命名建议使用解决人、上线日期和bug内容决定,如 hotfix/sbc_20230413_fixQueueFull
- hotfix分支属于临时分支,bug修复上线后可选删除
Git仓库的创建和使用
仓库的创建
根据现有的上线模式,抛弃之前svn的目录分层来区分多版本的结构,新Git仓库将使用单套代码多环境配置的模式,舍弃ver和branch文件下的未上线功能代码和备份,只保留tag下与线上环境一致的代码作为新Git仓库的开始。如果svn舍弃的代码中有未来准备上线的代码,则需要根据之后的开发规则重新手动合并到新的Git仓库中来。迁移或创建Git仓库步骤如下:
- 在码云中在对应模块中创建工程仓库。一定要创建.gitignore文件并根据项目开发中IDE或编译过程中产生的杂余文件作对应的筛除,保持项目的干净整洁。建议创建README.md文件,其中编写项目启动和部署信息和项目简介,方便项目未来的对接和开发。项目创建完成后,中心仓库应该只有master分支,其中包含.gitignore和README.md两个文件。
- 开始搭建项目。将工程从码云clone到本地,开始在master分支构建代码,如果是从svn迁移项目,则需要从最新的tag目录下将代码拷贝过来。准备多环境配置并完善打包脚本,实现多环境打包。在master分支构建到可以胜任开发运行和各环境打包上线的基础上,就可以push到中心仓库进行行下一步操作了。
- 基于master分支新建develop分支,并将他们都设为保护分支,不允许push代码,只允许合并操作。
仓库的使用
到这里Git仓库就已经迁移完成了,之后master分支和develop分支大部分时间都将保持完全相同的状态。当然构建仓库的方式有很多种,码云也提了创建仓库时候选择多分支的选项,但是构造的结构也是大同小异,所以希望读者都够清晰理解每个分支的作用和意义,促进开发的效率和默契。 接下来就是最关键的部分了,根据工程开发参与者的数量和便利我们可以有很多种开发流程,我们把常见的几种流程都过一遍:
- 如果是极少的人开发,并且沟通便利、代码量也较少,这种情况你就算只使用master一个主分支开发都可以,只需要保证每次提交前拉去代码在本地处理好冲突再push即可。既然只有master一条分支,上线部署只需要从master创建tag发布即可。
- 如果是十人左右的小组并且项目处于有大量需求需要开发的起步阶段,大家如果都在develop分支开发测试,那可能当你想测试的时候就会发现代码中有其他人提交不全的代码,导致项目启动不起来或者功能紊乱,这种情况就需要每个人根据功能从develop分支中拉去一条属于自己的分支,如 feature/sbc_addMqTranfer 来完成自己的功能开发,开发测试完成后合并到develop分支,保证develop分支是最新功能的稳定分支。在保证了develop分支稳定可用的基础上遇到上线,我们只需要从所需功能完善的develop分上创建对应的release分支进行部署测试,如果develop还有功能尚未完成,则后续开发完成后再提交到develop分支再合并到release分支上,如果release分支测试出现问题,则可以删除release分支,在develop分支上重新解决后问题后再创建新的release分支测试即可。等到release分支已经完全测试完毕,则将release分支合并到master分支上并创建tag,一次上线流程就此完成。
- 如果目前处于维护阶段的项目,需求较少也不固定并且不强制必须上线的情况,我们可以保证master和develop与生产一致保持一致,如果有明确的上线日期,如四月十三日,我们可以先从develop创建 release/20230413 分支,再从该release分支下创建对应开发功能的feature分支进行开发,开发完毕后合并到release分支等待上线。如果不知道准确的上线日期,则先从develop分支上拉取feature分支开发,等上线日期确定后再创建release分支并合并进去。至于和第2种的区别在于,我们并不着急将release分支合并到develop和master分支上,因为避免临时不上或者上线失败回退而导致污染了develop和master,在上线成功之后再将release分支合并到devlop和master并标记tag。
当然每个公司和团队的Git流程多少都会存在区别,但都是对于项目上线流程的妥协,所以无论流程是如何的,只要我们能保证代码上线的正常流转,就是好的流程。
常见场景处理步骤
-
四月十三日上线需求
- 从 master 创建 release/20230413 分支。
- 从 release/20230413 分支创建 feature/sbc_addFunction 分支进行开发。
- 开发完成后提交到中心仓库并创建从 feature/sbc_addFunction 分支到 release/20230413 分支的pull request 请求进行审核,审核不通过则继续在 feature/sbc_addFunction 分支上更改,之后重新提交pull request。
- 审批通过后合并分支并删除 feature/sbc_addFunction 分支,从 release/20230413 分支上准备上线介质。
- 待上线完成之后,管理员将 release/20230413 依次合并到develop和master分支上,并在 master 打上20230413的taf,删除 release/20230413 分支。
-
未知时间上线需求
- 从 develop 创建 feature/sbc_addFunction 分支进行开发。
- 等待确定上线日期后,从 master 创建 release/20230427 分支。
- 创建 feature/sbc_addFunction 到 release/20230427 的 pull request请求进行审核,之后就与第一种情况相同。
-
你和其他人一起开发四月十三日上线的任务
- 从develop创建 release/20230413 分支。
- 从 release/20230413 创建 feature/sbc_addFunction 分支开发。
- 开发完成单独测试完成后,每个都需要发起到 release/20230413 分支的 pull request 审核,但是后合并的人可能就需要解决两个人冲突的代码部分。冲突解决之后合并,接下来也是和第一种情况相同。
-
很早一个需求闲置了好几次上线,而这次需要四月十三日上线
- 假如之前从 master 分支创建的 feature/sbc_addFunction 功能落后了好几个上线版本,首先创建 release/20230413 分支。
- 从 release/20230413 创建 feature/sbc_deleteProduct 分支,因为 release/20230413 和 feature/sbc_addFunction 分支源头都develop分支创建,Git存在快照记录这两条分支前后文件变动,所以直接先将 feature/sbc_addFunction merge合并到 feature/sbc_deleteProduct 上并删除 feature/sbc_addFunction 分支,之后继续在 feature/sbc_deleteProduct 上开发。
- 开发完成后创建到 release/20230413 分支的pull request 评审,之后就和第一种情况相同。
讲在最后
虽然长远存在的分支只有master和develop分支,但是现在的设计迟早会因为各种挑战和原因而使仓库变得越来越笨重和复杂,所以规范存在的意义是当新的问题出现的时候,我们能以一个相对规范的状态转换到下一个规范中来,而不是完全的废弃重构,这将由我们未来一起努力。