背景

最近公司里多项目并行的时候, 发现在以前组管理的感觉比较混乱的分支方式(多个项目并行的时候, 同一个组件的代码需要维护多套分支)居然其实算是一个比较好的实现了...

这里的分支反而更加混乱. 索性梳理一下分支到底应该怎么管理, 才是最佳实现.

下面这部分是我目前的理解.

分支的场景

据我目前接触到和理解的, 会有以下几种常见的场景. 考虑到这里主要的障碍在于分支管理, 暂时假设一个组件的维护人员就是一人, 暂时跳过多人维护一个组件情况下的merge障碍问题(其实这块也比较要求模块设计的解耦, 多人改同一段代码这种情况本就不好合并, 我的理解是从设计上尽量避免对同一行冲突的修改). 根据[^6]中可知, 良好的模块化基本不会遇到代码分支带来的相同行修改的隔离问题.

  • 一个分支对应一个项目, 包含多个组件的并行开发
  • 多个分支对应多个并发项目面向不同业务场景, 同一套组件
  • 一个项目对应多个组件分支, 各组件并行开发
  • 多个组件对应多个主分支, 多个项目再各自开出对应的项目分支
  • 上面几项中, 公共组件在多个项目中的使用
    • 项目中只是用公共组件的发布版本
      • 公共组件维护一个私源库, 每次迭代发布一个版本.
      • 发布后的缺陷通过更新patch, 更新rpm包等形式, 如果各项目有涉及缺陷, 使用最新的组件包更新即可.
      • 优点:
        • 独立性强, 不需要因为业务项目拉出分支, 也进行项目拉出
      • 缺点:
        • 组件调试不便.
    • git subtree
      • 将一个目录自动提交到多个项目分支中的同一个组件目录下
      • 个人只处理一个分支,但是实际上项目有多个分支.
        • 这个感觉是一个比较好的处理手段.
    • 独立分支维护
      • 为了避免其他使用者对公共组件更新的感知不及时, 可以通过webhook等方式进行通知
  • 依赖第三方组件如何管理问题
    • 是单独维护一个分支用来记录使用的库及其版本的下载路径
    • 还是直接把库提交到分支中.

版本发布模式

  • 项目制发布模式: 项目制发布模式, 预先确定功能特性, 在所有功能开发完成后进行版本发布
  • 发布火车模式: 大型套装分发类软件, 各部门之间互相依赖, 约定版本发布的时间
  • 城际快线模式: 固定版本发布时间和质量维度, 时间较短

我理解, 项目制和发布火车模式有点相近. 都是约定一个集成时间, 开始各功能提交进行集成.

而城际快线就是高频集成的持续集成模式那种吧.敏捷开发?因为高频集成, 所以重构代码带来的代价也少, 这种比较贴合代码架构变更频繁的场景倒是.

分支管理的用途

  • 一个长期稳定迭代的基线分支
    • 这个分支只有当项目发布完毕时才合入代码.
  • 项目进行中的不稳定的开发分支
    • 这个分支在项目开启时,从基线拉出
  • 项目发布后的缺陷修复所需提交的分支
  • 定制项目的一些特殊需求无需合入基线.

潜在的问题

  • 当一个项目开发中时, 开启了另一个项目, 需要用到目前正在第一个项目的分支中开发的功能

    • 是否应该从项目分支再创建一个分支呢?
    • 还是从基线拉出分支, 然后再从当前正在开发的分支合并功能代码过去呢?
      • 根据现在的理解, 这个选择更合适, 分支统一从基线拉出, 这种分支流图更合理.
  • 当一个功能即将开发完毕时, 但是由于对接方面的人时间计划来不及处理了,他的功能没有上车,这样的话, 对于我们的代码应该怎么处理呢?

    • 我的理解是git的话可以在本地或是自己的一个branches里提交, 然后等到需要合并时, 再合入项目分支
    • 或者可以通过stash暂存区来处理这个问题.
    • 如果是svn, 是不是就只能注释这部分代码了呢?
      • 似乎也可以像git一样, 创建一个自己的分支先提交, 但是这样的话, 如果每个人都有创建的分支的权限的话, 似乎就会比较混乱了把?
        • 但是似乎这个也算是一个比较好的实现了.
      • 毕竟不像git有约定的特性分支, 只能自己拉自己的特性分支了.
  • 公司研发了一套svn插件, 导致通过git-svn来完成本地使用git这个逻辑不太可行.

  • 代码合并的最大成本主要是在于工具吗?

    • 并不是, 是在于开发时, 是否考虑过和基线的兼容性问题, 基线理论上除了缺陷, 不应该有其他的操作合入

通用思考

从主分支里拉了一个新分支出来,在合并回主分支之前,必须持续地把主分支的更改尽早尽快合并到新分支。新分支永远保持 最新主干代码+新模块代码 的状态。

其实的确是对的, 如果基线修改了, 那么就应该尽快把基线的一些修改合并到你当前的分支中去, 避免将来无法合并

因为你merge代码的时候,用BC除非没有冲突的文件,只要有add和delete操作的文件你都要逐个逐行进行处理啊,更别提有冲突的文件了。用git做merge无冲突文件且版本号高于master分支就自动帮你解决了,你只需要解决冲突就行;

git合并分支容易的原因是,要经常和master分支merge,这样把冲突消灭在萌芽状态。

git可以合并commit到一个后来被修改过的文件>

Git可以修改和重构历史提交:使用Git本身的reset以及 rebase 命令可以修改或者重整/重构历史提交,非常灵活。使用强大的 stg 可以使得历史提交的重构更为简洁,如果您对 stg 或者 Hg/MQ 熟悉的话。

大厂文章

美团单周迭代

  • 定期需求评审
  • 多版本多需求并行开发(在需求分支内开发)
  • 分支
    • release分支
      • 立项时从stage分支拉出
      • 成果物从这个分支构建.
      • 发版后合入到Stage分支.
      • 其他开发中的分支也合入该分支的最新代码
    • stage分支
      • 承担稳定的代码功能的归档
    • 通过jenkins job来完成分支的管理

git代码分支模型

git flow

  • 基线分支只合稳定以后的功能
  • 各项目的dev分支, 存放满足需求的feature的开发, 稳定后打tag, 合回基线
  • release分支, 从dev拉出, 包含所有功能, 处理发布所需, 完毕后打tag合回基线及dev分支
  • hotfix分支, 修复后, 合入到上述所有分支

优劣势

  • 流程清晰
  • 管理严格
  • 长期分支的同步开销较大, 不适合快速发布

github flow

  • 只有master分支, 只有部分管理员有提交权限, 其他人通过在自己分支完成功能后提交PR, 通过评审和自动化测试进行兜底
  • 各feature及缺陷修复分支

优劣势

  • 分支简单, 适合快速迭代
  • 不适合多环境多版本项目并行产品

gitlab flow

  • 似乎和git flow有点类似, 多出了production, release等分支?

TBD flow(Trunk Based Develop)

  • 开发及缺陷修复基于trunk, 只有快速发布, 完全没有分支管理

TBD++ flow

  • 基于功能的主分支
    • trunk和feature分支需同步更新
    • trunk分支有自动化测试自动执行
  • 基于发布的release分支
    • release分支发布后打Tag, 但依旧长期运行, 如果发现缺陷, 往这个分支及master分支合入缺陷修复, 这个发布分支打新的tag

todo: patch管理定制/上游代码, 是否可行?

巧用svn create patch(打补丁)方案解决定制版需求_golden_lion的博客-CSDN博客

Reference

  1. Git代码分支管理模型 - 简书
  2. (18 条消息) git合并分支,为什么会比svn容易? - 知乎
  3. 一个 Git 分支协作模式的进化故事 – Gitee 官方博客
  4. 客户端单周发版下的多分支自动化管理与实践 - 美团技术团队
  5. 【读书笔记-017】持续交付2.0之集成分支策略 - 简书
  6. Martin Fowler三万字解读源代码分支管理模式_ITPUB博客
  7. (18 条消息) Git 相比 svn 和其他版本管理工具的核心优势有哪些? - 知乎