工作上一直使用git作为代码版本管理工具,但从来没掌握好它。最近我负责的这部分代码管理越来越混乱,掌握一套正确成熟的git工作流程几乎是迫在眉睫的事情。

git 的基础使用就不赘述了。大概每个程序员都会花几个小时掌握 git 的基础操作,再花几周去实践和熟悉吧。
首先推荐两篇文章:

如果你没有遇到过多人协作下代码管理混乱、想要 release 新版时却交不出一份能 work 的代码,读这两篇文章可能不会很有 sense。但你只要遇过一次版本危机,再硬着头皮连续加班到凌晨一两点,回头来看就会很有感受。

上面两篇文章其实讲了2件重要的事:

  • 根据你的项目性质来决定工作流(git flow / github flow / gitlab flow)
  • 在一个固定模式下,git如何规范地工作


由于我在一家制造业企业,RD 只需隔一段时间 Release 一个 FW 版本给产线即可。比起敏捷地迭代,版本的稳定性更重要。传统的 git flow 是适合我们的。

在 git flow 框架下,有2个长期分支:

  • 主分支master
  • 开发分支develop

master名为master,却并不是日常工作的基础分支,而是一个经过验证的稳定分支。随时可以用来发布。
与master平行存在,内容几乎相同但又略有超前的,就是develop分支。平日的开发必须基于develop分支进行。在git flow框架下,当一个新的需求产生时,你基于最新的develop拉出一个 feature/xxx 分支,进行开发,功能完成后,再合并回 develop。(合并后 feature/xxx 分支自然消亡)

3种短期分支(完成开发后,合并进长期分支,然后删除):

  • 功能分支(feature branch)
  • 补丁分支(hotfix branch)
  • 预发分支(release branch)

feature 只能从 develop 拉出,然后合并进 develop。
hotfix 只能从 master 拉出,然后合并进 master 和 develop。
release 则是从 develop 拉出,进行测试,完成验证后合并进 master。

当 git flow 进行 release 时,它实际做了2件事:把从上一次 release 至今的 develop 改动经过验证后合入 master,再反向把 master 合并回 develop 确保两边同步。
为什么要反向 merge 一遍,因为 release 过程中若测试出一些问题,就可以直接在 release/xxx 分支上进行修改,而这个改动是没有发生在 develop 上的。所以 release 分支在删除时会保证这些改动也被同步到develop。

在这样的设计下,master 是稳定的,它受到 release 规则的保护,除非发生 hotfix,就只有经过测验的 release 分支才能合进 master。
而 develop 分支则相对比较敏捷,根据需求拉出 feature branch 后,开发者可以专注于自己的子任务,把兼容性等全局测试交给 release 分支去负责。

使用 git flow 相关工具,可以帮助规范这个流程。例如,工具会禁止你基于 master 拉出一个新的 feature 分支,因为新 feature 总是应该基于 develop 分支来开发,若要紧急修补某个bug,你应该使用 hotfix。
一些git flow工具(如gitflow-toolkit),还可以规范你的commit,确保commit信息清晰有效,能被script解析。这样你就能使用现成的工具(git-chglogconventional-changelog),自动生成change log。这在 release 正式版本的时候是很有用的:


以上是我理解的 git flow 实践。在应用中发现它也对使用者提出了一些要求:

  • 无论是否使用工具辅助,所有人都需要按规范格式进行commit(参考: Angular 社区规范
  • 每一项逻辑上独立的改动,应归属于一次单独的commit
    (不要在一个feature分支下进行多项任务的开发;若有多次commit都是关于同一个修改项目,应先squash再合进develop;尽量让每个 commit 都是一项独立、完整的改动,可以方便debug/release时进行cherry-pick和rebase)
  • git flow tool 大多是基于 Linux 系统。win下的开发者需要自我约束。

git flow 仍在实践中学习。有新的理解会再更新。