首页 / 资讯中心 / 文章详情

Git工作流规范实战:分支策略、提交规范与代码评审指南

Git工作流规范实战:分支策略、提交规范与代码评审指南 ★ FEATURED ARTICLE
1. 为什么你的团队需要一套Git工作流规范先说一个让我印象很深的场景某团队的项目已经做了半年代码仓库里同时挂着十几个长期分支main分支很久没有合并过每个人都从develop拉分支但合并回来的时候经常冲突。团队成员之间最常说的话不是这个功能怎么实现而是你把我代码覆盖了或者这个文件谁改的。到了发版那天所有人盯着main分支不敢动因为没人知道里面到底是什么状态。这不是个别现象而是很多开发团队会遇到的问题。问题不在于Git本身而在于团队里缺少一套统一的工作流规范。Git是分布式版本控制系统它的强大之处在于灵活但灵活意味着每个人都可以按照自己的习惯来操作。有的人习惯直接往main上推有的人喜欢把提交信息写得像散文有的人合并分支从来不删除这些都是潜在的风险点。在继续往下读之前我想先说明这套规范适用的场景它适合10人左右的技术团队以功能迭代为主需要同时维护一个稳定线上版本并且希望逐渐引入代码评审和自动化检查的团队。如果你是一个人做个人项目那Git怎么用都行不需要规范来约束如果你的团队已经有一套成熟的流程那么这套规范可以作为参考对照取长补短。我待过几个不同规模的团队也亲眼看到过没有规范和有了规范之后的差距。今天这篇文章我会结合自己实际推行Git工作流规范的经验把分支策略、提交规范、评审流程、合并策略、CI/CD衔接以及常见坑位全部讲透。里面涉及的命令我都会给出可复制的完整版本你不需要自己再去拼装。而且我在每个环节都会说清楚为什么要这么做因为只知其然不知其所以然规范就很难真正落地。2. 分支模型设计让仓库结构一眼就懂2.1 最常用的Feature Branch模型在讲解我们最终采用的分支模型之前先说清楚为什么不能直接所有人都往master分支上提交。master或者main分支是一个仓库最核心的分支它应该始终代表当前线上可发布的版本状态。如果所有人都直接往这个分支上提交会出现几个问题一是没有评审环节任何错误都会直接进入主干二是并行开发的多个功能会相互干扰A的未完成代码可能影响B的联调三是出了线上事故很难回溯因为你不知道是哪一次提交导致的。这就像一扇门所有钥匙都能打开安全性只能靠自觉来维持。比较通用的做法是引入develop分支作为集成分支所有的feature分支从develop拉出完成后合并回develop。develop分支上的代码经过充分验证后再合并到main分支形成发布版本。这其实就是基于Git Flow简化后的模型核心思想是开发在feature分支上进行集成在develop分支上进行发布在main分支上体现。用一个比喻来理解main分支就好比公司对外发布的官方公告develop分支是内部定稿区feature分支则是各个小编手头的草稿。2.2 分支命名规范与身份标识分支光有模型还不够名字本身也要有规范可循否则看着分支列表根本不知道这个分支是干什么的。我见过团队使用test、fix、asdf这种名字时间一长根本分不清。规范的命名方式需要包含三个信息分支类型、功能标识、作者标识。格式大概是这样的feature/用户登录功能-张三或者用更加简洁的英文命名feature/user-login-zhangsan分支类型我们约定以下几个feature用于新功能开发fix用于缺陷修复docs用于文档更新refactor用于代码重构。功能标识一般对应一个需求编号或者一句话描述作者标识直接写上开发者名字的拼音缩写或者花名方便追责。不过这里有一个注意点如果团队成员较多、功能迭代频繁作者标识可能会让分支名变得很长。我们后来采用的做法是在拉分支的时候带上自己的花名而在合并之后统一清理分支所以长度问题不算严重。规范分支命名不是强迫症行为它带来的实际价值是任何人打开分支列表不需要挨个问就可以判断每个分支的类型和用途。尤其是在团队规模扩大到三四十人的时候分支数量可能同时有二十几个没规范的话看着就头皮发麻。2.3 保护分支设置光有命名规范还不够要从机制上防止操作失误就需要借助代码托管平台提供的保护分支功能。目前主流的托管平台都支持这个能力它们的名字叫分支保护规则或者Branch Protection Rules。我们团队在main和develop上开启了保护规则是不允许直接推送所有变更必须通过合并请求Merge Request / Pull Request的方式合入。除此之外还要求通过至少一位评审人的审核并且CI流水线必须跑通过。这里需要补充一下为什么保护规则要强制不允许直接推送这一条。团队里难免出现某个开发者在赶进度的时候觉得走流程太麻烦直接用git push origin main把本地代码推上去。这种做法破坏性极大因为被保护的分支承载的是团队的公共成果绕过保护规则相当于跳过集体审查风险全部都压到了线上环境。所以保护分支的第一条规则就是不直接推这比后面那些自动检查还重要。在配置保护分支的时候很多人会忽略一个细节受保护分支的允许合并权限通常是保留给Maintainer角色的也就是团队的负责人或者技术组长。这意味着普通的开发者如果分支修改到位了还需要等Maintainer点击合并按钮。这个小流程保证了关键合并动作都经过管理层把控但也带来了一个协作摩擦点后面我在常见问题里会讲到怎么处理。3. 提交信息规范让每次变更都有迹可循3.1 小步提交的哲学分支规范解决的是分支从哪来、到哪去的问题提交规范解决的是代码怎么一步步进去的问题。有不少开发者习惯一次性改很多文件然后提交一条信息完成登录模块就完了。这种大提交的坏处不是立刻显现的而是等到你需要回滚某个功能的时候才意识到因为这一个提交里可能包含了界面改动、后端接口改动、数据库脚本改动如果其中只有某部分出了问题你很难精准地只撤销那一部分变更。另外评审人面对一个改动了几十个文件、跨越多层的巨型提交时根本没有耐心和精力逐行看完评审质量会大打折扣。正确的方式是小步提交。所谓小步我个人的理解是提交粒度小到这个提交做了一件逻辑上完整的事。比如实现登录模块时可以拆成新增用户登录接口、添加登录页表单校验、绑定登录接口与表单三个提交而不是一个大提交。这种做法带来的直接好处是代码回滚变得非常精准评审人也能按提交逐个理解你的实现思路。小步提交从执行层面还匹配了一个高频场景当你开发到一半发现思路走错了如果之前是一个个小的提交你只需要回退到最近的一个正确提交就可以如果是大提交想回退都找不到安全的回退点。这就像写文章是一个字一个字敲出来的而不是一段话一次性生成出来的出错了也知道改哪里。3.2 提交信息模板避免无意义的提交说明提交信息是提交的门面也是评审人快速理解变更的第一手材料。很多团队对提交信息只有一个要求别写得太随意。但随意的标准是什么模糊不清所以我更倾向于提供一个提交信息模板。我们在团队内推行的模板是类型: 简述 详细说明类型feat、fix、docs、style、refactor、test、chore简述用一句话说明本次提交做了什么尽量控制在50字以内详细说明可选如果有必要说明背景、影响范围、注意事项则补充在第二段举几个实际的例子fix: 修复登录接口未处理token过期的情况 Token过期后后端返回401前段重新拉取刷新接口避免用户被强制登出。feat: 新增订单导出Excel功能如果团队希望提交信息更结构化也可以引入流行的Commitizen工具通过交互式命令行引导开发者填写规范的提交信息。但我的看法是工具是辅助真正决定行为习惯的还是规范和团队认同。工具能降低门槛但规范本身需要团队讨论并达成共识。3.3 文拉过程的一个注意点提交信息规范落地时最大的阻力不是记不住格式而是很多开发者在写信息时只会写update或者修改这种毫无信息量的动词。对于这种情况光靠规范文档是不够的我建议在Code Review的检查清单里加上一条提交信息是否能够描述本次变动的核心意图。如果提交信息不合格评审人可以直接给出Request Changes的评论不用优先讨论代码本身。一旦评审环节愿意卡提交信息团队成员就会慢慢开始注意有一两个迭代的时间习惯就能养成。还有一个细节我要特别提醒不要在提交信息里写#符号加一串数字这种内容除非这些数字对应的是你们团队沉淀下来的需求文档或缺陷单号。对没有上下文的读者来说#3892并没有任何意义没有人记得住3892是什么。如果有需求编号要用类似需求订单导出编号#1024的方式让含义自解释。4. 分支开发全流程从拉分支到合回4.1 标准流程八步走有了分支模型和提交规范很多开发者的第一反应是流程复杂了效率变低了。实际上标准化的开发流程带来的整体效率提升远大于它设置的门槛。下面是我在团队内推行的一套完整流程一共八步从最新的develop分支拉取新分支git checkout develop git pull origin develop git checkout -b feature/user-login-zhangsan开发过程中保持小步提交每个提交信息符合规范开发完成后自己先把主分支最新的代码合并进来git merge origin/develop在本地解决所有冲突并做一轮自测推送分支到远端git push origin feature/user-login-zhangsan发起合并请求目标分支选择develop描述清楚改动内容和测试范围等待至少一位评审人通过CI流水线跑过合并分支删除本地和远端feature分支这个流程的最大特点是把本地验证和评审合入做了清晰的切分。前五步是开发者自己可以主导的后面三步是团队协作环节。很多团队在实际执行时最常跳过的是第3步和第4步直接把自己开发的分支推上去发起合并请求结果冲突数量惊人CI也经常失败。省这几分钟的时间后面要花几倍的时间去解决。4.2 本地不死守陈旧分支有一个在很多团队出现的场景某个功能分支开出来之后由于需求变更或者优先级调整被搁置了很久。等重新回到这个分支继续开发的时候它已经和develop的差异非常大合并冲突多到根本不想处理。面对这种情况我的建议是果断放弃旧分支从最新的develop重新拉一个新分支然后在新分支上挑拣cherry-pick自己需要的提交。如果觉得挑拣太麻烦也可以把旧分支的代码用补丁方式带过来。这里分享一个简单可操作的方式git checkout -b feature/new-task-zhangsan 从最新develop拉取的新分支 git cherry-pick A..B其中A..B是两个提交哈希之间的范围。如果你只知道旧分支名可以用git log find来找到对应的提交范围。这个操作的精髓在于保留历史痕迹同时脱离开陈旧的上下文环境。我自己在团队里遇到死分支复活的情况基本都用这套方案效果很好。4.3 多人协作同一分支的技巧有时一个功能比较复杂需要两个人甚至三个人在同一个feature分支上协作。这个场景下需要约定几条规则否则照样会出问题协作的分支要频繁推送、频繁拉取避免在同一批文件上各自修改过久推送到远端之前先拉取远端最新代码并解决冲突不要直接强推每天收工前把当天进度推到远端防止本地丢失遇到关键文件大家都改了沟通优先级由一个人先合并牵头完成最怕的是两个人闷头各改各的一周之后才开始同步那时基本已经陷入冲突泥潭。Git本身处理文本冲突的能力尚可但处理大范围逻辑冲突的能力有限源头预防比事后解决重要得多。5. 代码评审规范与质量保障的关键闸口5.1 评审人和评审流程怎么定代码评审在整个工作流中扮演着质量闸口的角色。没有评审的团队代码质量完全依赖个人水平和自觉性而有评审的团队至少每次变更都有第二双眼睛盯着。评审流程很需要设计否则它会流于形式。我见过的最典型的失败案例是合并请求创建之后有人点了Approve但这个评审人根本没有看过代码或者只看了文件列表因为大家都急着上线。这个问题的根源在于评审的责任没有被明确以及评审的清单没有被标准化。在团队协作里我们在合并请求模板中内置了这样一个检查清单发起人必须勾选[ ] 本次改动是否关联具体需求或缺陷[ ] 是否在本地完整运行过测试且通过[ ] 是否有需要同步更新的文档[ ] 是否考虑过异常情况和边界输入[ ] 提交信息是否符合团队规范同时要求评审人在评审时至少检查以下方面逻辑正确性、边界条件、安全隐患、可读性和可维护性。评审人需要把有问题的地方直接指出当作自己的工作而不是交给流水线机器去判断。5.2 评审效率的三个抓手评审容易耽误时间是大家不愿意做评审的头号原因。这里分享三个提高效率的抓手第一控制单次评审的代码量。理想情况下单次合并请求的代码改动量不超过400行包着的新文件不要超过10个。超过这个量级评审人很难保持注意力。如果某个合并请求改动巨大多半是分支开发周期过长提交粒度太粗。第二用先评思路再评细节的方式。评审人看到合并请求后先看描述和主要变更理解需求背景再有针对性地看关键逻辑而不是逐行过去。这样能做到快而准。第三设置评审时限。合并请求发起后相关的评审人要在4个工作小时内给出初审结果。超时的合并请求自动升级到技术组长处理。这个时限和升级机制的设置有效改善了挂起无人问的状态。5.3 Merge Request模板的重要性合并请求模板是一个成本极低、收益很高的规范工具。很多代码托管平台允许仓库自带模板当开发者发起合并请求时模板内容会自动填入描述框。我们的模板字段是这样的标题[功能/修复/重构] 简述 背景为什么做这次改动 改动内容涉及哪些模块核心逻辑说明 测试情况本地测试覆盖情况 影响范围有无外部依赖变化是否需要数据库变更 注意事项关联文档、接口变更、UI适配说明模板的价值在于把组织所见的主动沟通义务落到了发起人身上避免评审人对着代码猜来猜去。一个认真填写了模板的合并请求评审人可以节省大量时间反过来一个空白描述的合并请求本身就是发起人态度不认真的信号。6. CI/CD衔接让规范自动执行6.1 Husky lint-staged提交前自动检查人总是会犯错的所以规范能够自动执行的部分应该尽量自动化。第一道自动化防线是Git Hooks也就是Git的钩子机制。利用pre-commit钩子我们可以在代码提交之前自动运行检查和格式化。前端项目比较常用的组合是Husky加lint-staged。Husky负责安装和配置Git Hookslint-staged负责只对暂存区里的文件执行检查操作。为什么要用lint-staged而不是对整个项目跑一遍检查因为大项目的ESLint或者Stylelint检查整个仓库可能要几分钟开发者不愿意每次提交都等而只检查暂存区文件通常只需几秒钟这个体验的差距决定了工具能不能被坚持下去。示例配置大概长这样{ husky: { hooks: { pre-commit: lint-staged } }, lint-staged: { *.{js,vue}: [eslint --fix, git add] } }这里的含义是提交前对暂存区中的js和vue文件执行ESLint自动修复修复后的变更重新加入暂存区然后才允许提交。这个小机制直接拦截了一大批低级错误比如未使用的变量、明显的语法问题、不规范的格式等。git add放在数组最后是为了把eslint --fix的结果更新到暂存区这个细节很多初次配置的人容易漏掉。引入预提交钩子时要注意一个问题不要在一开始就配置特别严格的规则否则团队里每个人的本地上都会出现提交被拦改半天才能过的现象大家会非常反感。比较稳妥的方案是先在提交阶段只做格式化修复把错误检查和更严格的规则放到CI阶段逐步推进。6.2 流水线中的代码质量门禁提交钩子覆盖的是开发者本地行为CI流水线覆盖的是团队公共分支的行为。我们在流水线中设置了一道代码质量门禁包含以下几个步骤安装依赖并做依赖检查执行单元测试和集成测试运行静态代码扫描工具构建产物并检查构建是否成功生成测试覆盖率报告任何一个步骤失败合并请求就处于不可合并状态。这个门禁的最大价值在于让机器去执行重复、机械、客观的检查让人力聚焦于需要判断力和经验的地方。以前很多团队把代码扫描、测试都压到评审人身上评审人既要看逻辑又要管格式。在CI阶段还要单独说一句覆盖率下降阈值应该和你现在的实际水平匹配不要拍脑袋定一个遥不可及的数字。我们团队一开始把覆盖率目标定得太高为了赶目标所有人都去写没有任何断言价值的测试覆盖率数字是上去了质量反而更差。后来调整策略核心模块覆盖率必须达标非核心模块不强求。这样测试才真正发挥保护功能。6.3 自动化版本管理与变更日志如果团队的发布频率高那么版本号和变更日志的维护也应该进入规范流程。常见工具有标准版本库管理工具例如semantic-release或者standard-version它们可以根据提交信息自动推断版本是主版本升级、次版本升级还是修订版本升级。在使用这类工具时提交信息规范就变得更加重要因为工具的语义解析依赖提交信息中的类型前缀。比如fix: xxx会被识别为修订版本变更feat: xxx会被识别为次版本变更BREAKING CHANGE标记会触发主版本升级。可以说提交规范不再是好看不好看的问题而是直接决定了版本号的正确性。自动化版本管理给团队带来最直观的收益是发版时再也不用人工去比对代码改动范围、翻阅提交历史、手动填写变更日志了。整个发布路径变成合并到main - 触发流水线 - 自动打标签并生成变更日志干净利落。7. 常见问题与排查技巧实录7.1 低频但破坏性大的操作自查这一节我整理自己在实际工作中遇到比较多的问题用表格的形式分享出来同时附上解决思路和预防措施。问题现象可能原因解决方案后续预防推送到远端被拒绝本地落后于远端或分支受保护先拉取远端最新代码处理冲突后再推送推送前先养成pull的习惯代码冲突很多且难解分支开发周期过长基线下沉及时合并主干代码缩短分支生命周期分支存活时间不超过3天合并后功能消失某个分支删除了公共代码合并时未保留检查合并冲突解决历史大数据集合并时请第二人复核提交信息看不出改动意图提交规范没有被严格执行评审时要求补充或修改提交信息将提交信息规范纳入评审清单覆盖了别人的代码使用了强推覆盖远端分支用普通提交替代强推避免使用git push -f限制强推权限特殊场景走人工申请这个表格里的第七行放不下其实强推这个话题值得单独说。在规范的团队工作流里除非你是在修复自己刚推上去的错误提交并且确认没有其他人在那个分支上干活否则严禁使用强推。我曾经见过一个场景某个开发者为了让自己的分支保持干净用了git rebase之后强推结果另一位同事基于这个分支拉出的子分支完全失效白做了两天功能。Git的强推能力本身是好的但它必须用在正确且受控的场景不然就是一场事故。7.2 解决合并永远冲突的系统性方案很多团队的说法是我们项目里总是有文件一合并就冲突。细查之下这些冲突大体集中在两类文件上一是配置文件比如依赖锁定文件二是接口定义文件多人在同一接口上频繁增删字段。针对配置文件解决的思路是把它当作只读文件来看待。团队推行的做法是配置文件的变更必须单独提交不能混在功能改动里升级依赖库时由一个人统一操作并单独走合并请求。这样一来这类文件的变更频率降低很多冲突自然减少。针对接口定义文件冲突往往是因为缺乏接口设计评审流程。我试过一个挺有效的方式把接口定义文件纳入专人复审核查范围他并不是全盘的代码负责人但专门负责检查接口变更是否会影响其他模块。在合并请求模板中我们专门加了一行是否包含接口变更联系人是谁。这个机制实施之后接口文件的冲突率下降了一个数量级。7.3 新老交替与规范守成团队里推行规范最容易遇到的第二类矛盾是新成员说流程太烦老成员说你们一开始就没流程。统一解决这个矛盾的办法是做一份团队级的Git协作手册里面把分支策略、提交规范、评审流程、CI门禁全部讲清楚新成员入职培训时花半天时间过一遍老成员犯了规也可以对照手册复盘。有些框架团队的实践甚至更进一步把Git手册放进仓库根目录的docs目录每次新建合并请求时模板都会提示阅读相关文档。更要补充的一点是规范本身不是一成不变的。团队的业务形态、研发规模、发布节奏会变化Git规范也要跟着演进。我们团队每季度会做一次工程效能复盘其中固定有一个环节是Git工作流哪些环节堵住了,然后针对瓶颈做出调整。比如有一段时间我们觉得评审的等待时间太长后来引入了轮值评审机制让资深开发者轮班处理合并请求大大缩短了排队时间。8. 最后再分享一点个人体会推Git工作流规范这件事本质上不是定一套规则而是改变了团队对代码主人的认知。以前很多人觉得代码是我写的我想怎么提交就怎么提交推行规范之后大家逐渐认识到代码是团队资产每次变更都长得像一份合规文件可以被追溯、被审视、被保护。一个有规范的仓库和一个没有规范的仓库差别的表面是流程内里是团队的工程素养。如果你所在的团队还没有一套成型的Git规范我建议你从下面三个动作开始第一先把main和develop分支保护起来关闭直接推送权限这一步改动虽小但机制上把随意合入的路径切断了。第二拉一个合并请求模板让发起合并请求的人必须说明需求和改动范围光这一步就能减少大量无效沟通。第三落地一个pre-commit格式检查不用很复杂能跑起来就够了。当大家的提交不再是随便拖进暂存区就完事前面所有的规范都更好推。从零星的操作习惯到全员遵循的规范这个过程不会太轻松它需要你反复提醒、复盘、调整。但等到某一天发布上线前不再有人抓瞎冲突不再是家常便饭新成员半天就能上手协作方式你就会觉得之前花在规范上的每一分钟都值得。
阅读完成 · 觉得有帮助?
咨询建站