Git 工作流实践方案探索

前言

Git 作为一个强大的代码管理工具,一直以来都是各大公司的首选,尤其是全球最大的开源社区 GitHub 将 Git用到了炉火纯青的地步。

在我们日常工作中,协同开发是最高效的一种方式,尤其是比较大的需求点以及功能,甚至是新项目的开发。这种情况下,Git 的使用无可避免的也会出现一些问题。

首先,项目开发容易存在的问题:

  1. Git 分支管理分支混乱;
  2. 工作流混乱;
  3. 没有有效的进行 Review 代码;

混乱的代码管理,对线上功能埋下了巨大隐患,而稳定性的前提就是要对代码进行有效管理,如何制定最符合团队风格的工作流成为了我们工作的重中之重!

接下来,我们就通过本文和大家一起来聊一下 Git 工作流。

本文的目录结构如下:

主流 Git 工作流对比

在这里,我总结了一下目前市面上几种主流的 Git 工作流:

  • 集中式工作流;
  • 功能分支工作流;
  • Gitflow 工作流;
  • Forking 工作流;

各种工作流都有各自的优缺点,没有最好,只有更合适。

集中式工作流

如果开发团队成员已经很熟悉SVN,集中式工作流让你不需要去适应一个全新流程就可以体验Git带来的好处。这个工作流也可以作为向更Git风格工作流迁移的友好过渡。

使用Git加强开发的工作流,相对于SVN有几个优势:

  • 每个开发可以有属于自己的整个项目的本地拷贝。隔离的环境让每个开发者的工作和项目的其他部分修改独立开来,能够自由地提交到自己的本地仓库,先完全忽略上游的开发,直到方便的时候再把修改合并上去。
  • Git提供了强大的分支和合并机制。不像SVN,Git的分支被设计成可以做为一种用来在仓库之间集成代码和分享修改的安全机制。

工作方式如下图:

集中式工作流以中央仓库master作为项目所有修改的单点实体,所有的修改都提交到这个分支上。此工作流只用到master这一个分支。

开发者先克隆master,在自己的本地项目中编辑文件和提交修改;但修改是存在本地的,和msater是完全隔离的。

要发布修改到项目中,开发者要把本地master分支的修改push到中央仓库中。注意push操作会把所有还不在中央仓库的本地提交都push上去。

功能分支工作流

功能分支工作流,这种工作方式是以集中式工作流为基础,再为不同功能开发分配单独的功能分支来进行的;这种工作流的主干分支仍然是 master 分支,但是开发者在进行日常需求开发时不能将代码直接提交到 master 分支上,一般是为特定的需求新建一个功能分支,并且取一个具有描述性的名字,例如:feat-add-new-page、issue-#94320,描述性的名称可以让其他开发者快速地明白这个功能分支的主要作用,提高不同开发者之间的协同效率。

功能分支工作流的核心思路是所有的功能开发应该在一个专门的分支,而不是在 master 分支上。这个隔离可以方便多个开发者在各自的功能分支上开发而不会弄乱主干代码。也保证了master分支的代码一定不会是有问题的,极大有利于集成环境。

同时,功能开发隔离也让 pull requests 工作流成功可能,一旦某个开发完成一个功能,不是立即合并到master,而是 push 到对应的功能分支上并发起一个 Pull Request 请求去合并修改到 master。

在修改成为主干代码前,这让其它的开发者有机会先去 Review 变更。这也就是说可以在更早的开发过程中就可以进行 Code Review。

一旦 Pull Request 通过了,发布功能要做的就和集中式工作流就很像了。

  • 首先,确定本地的 master 分支和上游的 master 分支是同步的。然后合并功能分支到本地 master 分支并 push 已经更新的本地 master 分支到中央仓库(在分支合入 master 之前,其它开发者还有提出建议和讨论的机会)。
  • 另外,如果你在功能开发中有问题卡住了,可以开一个 pull requests 来向同学们征求建议。这些做法的重点就是,pull requests 让团队成员之间互相评论工作变成非常方便!

Gitflow 工作流

Gitflow 工作流是目前非常成熟的一个方案,没有用超出功能分支工作流的概念和命令,而是为不同的分支分配一个很明确的角色,并定义分支之间如何和什么时候进行交互。它定义了一个围绕项目发布的严格分支模型,通过为代码研发、项目发布以及维护分配独立的分支来让项目的迭代过程更加地顺畅,不同于之前的集中式工作流和功能分支工作流的是,gitflow 工作流常驻的分支有两个:主干分支 master、开发分支 dev(master分支存储了正式发布的历史,而dev分支作为功能的集成分支),此外针对项目研发的各个阶段,也可以设定特定的分支。

当然你也可以用上功能分支工作流所有的好处:Pull Requests、隔离实验性开发和更高效的协作。

Forking 工作流

Forking 工作流是分布式工作流,充分利用了Git在分支和克隆上的优势。可以安全可靠地管理大团队的开发者(developer),并能接受不信任贡献者(contributor)的提交。

Forking 工作流与其它工作流截然不同。与其使用唯一的服务端仓库作为「中央」代码库,它给予每个开发者一个服务端仓库。也就是说每个贡献者都有两个 Git 仓库,而不是一个,一个私有的本地仓库和一个公开的服务端仓库。

Forking 工作流的主要优点在于贡献可以轻易地整合进项目,而不需要每个人都推送到单一的中央仓库。开发者推送到他们自己的服务端仓库,只有项目管理者可以推送到官方仓库。这使得管理者可以接受任何开发者的提交,却不需要给他们中央仓库的权限。

结论是,这种分布式的工作流为大型、组织性强的团队(包括不可信的第三方)提供了安全的协作方式。它同时也是开源项目理想的工作流。namespace 不同了,权限都在自己手里,成为 Fork 项目的 Maintainer。

如何优化工作流

优化 Git 工作流可以从以下几步做起:

  • 规范工作流程准则,提升工作效率;
  • Commit 规范;
  • PR 规范;
  • CodeReview 规范;
  • 附赠 Github 黑话;

规范工作流程准则,提升工作效率

相信大家都有相同的感受,日常开发中,每个人的开发习惯都不一样,千奇百怪的开发习惯极大程度提升了后续的代码的维护成本以及沟通成本,因此规范工作流程显得尤为重要。

Commit 规范

Git每次提交代码都需要写 commit message,否则就不允许提交。

一般来说,commit message 应该清晰明了,说明本次提交的目的,具体做了什么操作。但是在日常开发中,大家的 commit message 千奇百怪,中英文混合使用、fix bug 等各种笼统的message司空见怪,这就导致后续代码维护成本特别大,有时自己都不知道自己的 fix bug 修改的是什么问题。

基于以上这些问题,我们可以通过某种方式来监控用户的 git commit message,让规范更好的服务于质量,提高大家的研发效率。

commit message 格式:

    <type>(<scope>): <subject>
复制代码
  • type(必须), 用于说明 git commit 的类别

    常用的标识如下:

    feat:新功能(feature)
    fix/to:修复bug,可以是QA发现的BUG,也可以是研发自己发现的BUG
    fix:产生diff并自动修复此问题。适合于一次提交直接修复问题to:只产生diff不自动修复此问题。适合于多次提交。最终修复问题提交时使用fix 
    docs:文档(documentation)
    style:格式(不影响代码运行的变动) 
    refactor:重构(即不是新增功能,也不是修改bug的代码变动)
    perf:优化相关,比如提升性能、体验
    test:增加测试
    chore:构建过程或辅助工具的变动
    revert:回滚到上一个版本
    merge:代码合并
    sync:同步
    复制代码
  • scope(可选)

    scope用于说明 commit 影响的范围,比如数据层、控制层、视图层等等,视项目不同而不同。

    例如在Angular,可以是location,browser,compile,compile,rootScope, ngHref,ngClick,ngView等。如果你的修改影响了不止一个scope,你可以使用 * 代替。

  • subject(必须)

    subject 是 commit 目的的简短描述,不超过50个字符。

    建议使用中文(感觉中国人用中文描述问题能更清楚一些)。

    结尾不加句号或其他标点符号。根据以上规范 git commit message 将是如下的格式:

    fix(DAO):用户查询缺少username属性 
    feat(Controller):用户查询接口开发
    复制代码

以上就是梳理的 git commit 规范,那么我们这样规范 git commit 到底有哪些好处呢?

便于程序员对提交历史进行追溯,了解发生了什么情况。一旦约束了 commit message,意味着我们将慎重的进行每一次提交,不能再一股脑的把各种各样的改动都放在一个 git commit 里面,这样一来整个代码改动的历史也将更加清晰。格式化的 commit message 才可以用于自动化输出 Change log。

PR 规范

基于 Github Flow 进行协作时,如何基于完整、清晰的 Pull Request 进行沟通是其中关键一环。工具检查是最有力的保障,但代码之外的文字部分只能靠约定。

撰写一个合格的 PR, 应该满足以下条件:

  • 一个 PR 只围绕一件事情
  • 避免超大的 PR
  • PR 标题——概述此次 Pull Request 的目标
  • PR 说明——面向未来的 Reviewer
  • 详述需要哪些反馈(如果有的话)

一个 PR 只围绕一件事情

如果确有必要将几件事情(例如修改特别小、相互之间有依赖等)一起提交 PR,则需要列明具体每一件事情,确保 PR 说明涵盖了所有修改内容。

大片的代码格式整理要作独立提交(Commit),不要和代码修改混在一起,以便 Reviewer 能轻松查看干净的代码修改 diff。

避免超大的 PR

超过 1000 行修改行数的 PR 需要考虑是否能拆分为多个子任务分别提 PR(合理的程序结构设计也应该是解耦的)。

如果 PR 包含的提交数量过多,通常是开发过程掺杂了“尝试—修问题—换个方法再来”这样的重构反复。此种情况最好抛弃这些过程提交,新开分支逐个应用有意义的修改,然后提 PR。

PR 标题——概述此次 Pull Request 的目标

例如:尝试用 XXX 方法实现……、优化……、修复在 XX 状态下对 XX 的异常处理。

PR 说明——面向未来的 Reviewer

记住公司里任何人,任何时候都有可能来阅读这个 Pull Request,所以内容和语气都需要面向未来可能的 Reviewer,不要假定对方已经熟悉这些事情的前因后果。

酌情提供关于这些工作起因的说明,记得包含相关链接。例如跟特殊业务相关的地方,需要添加相关业务文档链接;处理了非常奇异的 Bug,就有必要附上相关线索、资料链接。

详述需要哪些反馈(如果有的话)

如:@某人过目一下代码/讨论某项技术实现/对设计的意见等等。

明确你何时需要反馈。如果这个 PR 还没有完成(仍有一些代码修改待推送)则需醒目注明,常见做法是给标题加上[WIP](施工中)的前缀。

CodeReview 规范

PR 提交以后,接下来就需要项目 Owner 来对 PR 的内容做 CodeReview。

CodeReview 目标和原则:

  • 提高代码质量,及早发现潜在缺陷,降低修改/弥补缺陷的成本;
  • 促进团队内部知识共享,提高团队整体水平;
  • 评审过程对于评审人员来说,也是一种思路重构的过程,帮助更多的人理解系统;
  • 是一个传递知识的手段,可以让其它并不熟悉代码的人知道作者的意图和想法,从而可以在以后轻松维护代码
  • 可以被用来确认自己的设计和实现是一个清楚和简单的;
  • 鼓励相互学习对方的长处和优点;
  • 高效迅速完成Code Review;

附赠 Github 黑话

  • PR Pull Request。 拉取请求,给其他项目提交代码;
  • LGTM Looks Good To Me。 代码已经过 Review 可以合并啦;
  • SGTM Sounds Good To Me。 同上;
  • WIP Work In Progress。 如果一个功能修改很大,可以在 PR 中标记 WIP 以告诉项目维护者这个功能还未完成,可以先 Review 部分提交代码;
  • PTAL Please Take A Look。 一般同时会 @SomeBody ,告诉他来瞅瞅是否有问题;
  • TL;DR Too Long; Didn’t Read。 一般用在长篇文章开头的总结部分,用于提示用户,这篇内容篇幅较长,如果不想深入探讨或时间有限,可以看总结。

参考文档

  1. 字节研发设施下的 Git 工作流
  2. Git 工作流的一些经验分享
  3. Pull Request 书写指南
  4. CodeReview规范
  5. 如何优雅地pull request
  6. Martin Fowler三万字解读源代码分支管理模式

Supongo que te gusta

Origin juejin.im/post/7050012586296737805
Recomendado
Clasificación