Git原理与分支管理实践

Written with Claude.

理解 Git 不应止步于记住命令。本文记录了两个动手实验——把 .git 目录的对象存进数据库、用 JS 重新实现 Git 核心操作——以此真正搞清楚 Git 在保存什么、操作什么。第二部分结合团队实际诉求,设计了一套基于 Git Flow 的分支管理方案。

原理理解

将 .git 存储到数据库(git-db)

Git 的存储本质是一个内容寻址的 KV 数据库,所有对象(blob / tree / commit / tag)都以 SHA-1 为 key,以 zlib 压缩后的二进制为 value。这个实验将 .git/objects 下的所有对象导入关系型数据库,直观地验证了这一点:每一次 git add 产生一个 blob 对象,每一次 git commit 产生一个 commit 对象和若干 tree 对象,分支和 HEAD 不过是指向某个 commit SHA-1 的指针文件。理解这一层之后,Git 的大多数"魔法"行为都变得可以推导。

用 JS 重新实现 Git(git-js)

在理解存储结构之后,用 JavaScript 重新实现 Git 的核心操作(init / add / commit / log / checkout),目的是验证对操作语义的理解是否准确。这个过程中最重要的收获是:Git 的"分支切换"本质上只是修改 HEAD 指针 + 用目标 tree 对象还原工作区,与任何网络、服务端都无关;而 merge 的核心是找到两个 commit 的公共祖先,再做三方合并。

分支管理

主流工作流对比

分支管理策略大体分为两类:Trunk Based DevelopmentGit Flow

  • Git Flow:维持 masterdevelop 两个长期分支,分别对应生产和测试环境。多版本场景下可从对应节点再建新的主分支并行推进。节奏稳健,适合有明确发布窗口的团队。
  • GitHub Flow:主干持续发布,feature 分支直接合入 main 并部署。是 Trunk Based 的精华版,对团队整体工程能力要求高,不适合多版本并行管理。
  • GitLab Flow:GitHub Flow 的演进版,在主干之外增加环境分支(如 productionstaging),主干代码向下游环境分支合并。相比 GitHub Flow 更适合有多套环境的团队,但对合并纪律要求较高。

代码管理诉求

  • 按窗口(功能清单)发布、单一生产版本
  • 支持多版本并行开发
  • 尽可能保留所有 commit

操作方案:基于 Git Flow

多版本并行开发策略

多版本并行开发通过以下约束保证代码继承关系的正确性:

核心规则:所有测试分支不得落后于 master

无论当前有多少个版本在并行开发,每个测试分支在提 MR 合入时,必须已将最新的 master 内容 merge 进来。这一约束确保了:

  • 任何一个版本上线后,其他版本的测试分支都不会丢失已上线的内容
  • 版本间的代码继承关系通过这条规则自然保证,不需要额外维护分支间的同步逻辑

执行时机:同步要求在提 MR 合入测试分支时即生效,而非上线前才处理,避免冲突在打包阶段集中爆发。

CR 注意事项:feature 分支 merge master 后,MR 的 diff 中会包含与本次功能无关的内容。开发者须在 MR 描述中注明是否包含 master 同步,方便 reviewer 聚焦在本次功能变更上,避免 CR 流于形式。

分支命名

  • master:最新 commit id 等价于当前生产版本
  • develop:单版本场景下的测试主分支
  • develop_vX:多版本并行时各版本独立的测试分支,对应独立的测试环境
  • release_日期:窗口裁剪的标准路径,当测试分支上同时存在多个功能但本次只上线部分时使用

代码提交

所有分支合入测试主分支前须经过 Code Review。通过拓宽 CR 参与人数来分散审查压力,保证代码质量。feature 分支合入时禁止 squash merge,保留完整的 commit 历史。

打包上线

若存在 release 分支则以 release 为打包源,否则以本次测试分支为打包分支。打包产物的后缀 commit id 即为 master 合并与 tag 的目标节点。

master 分支只允许 --ff-only 合并,确保其仅作为映射指标存在——所有 commit 均来源于经过复核的测试主分支。

典型生命周期(单测试分支场景):

feature → develop → (build & verify) → master (ff-only) + tag

平台配置

以下规则须在 GitLab/GitHub 分支保护里显式配置,不依赖约定:

规则 作用
develop_* 只允许 merge commit,禁止 squash 保留所有 commit 历史
master 只允许 ff-only 保证 master 是线性映射
feature 分支合入 develop_* 必须通过 MR + CR 保证上线质量
develop_* 不允许直接 push,必须走 MR 防止绕过 CR

最终效果

  • master 与 tag 共同构成所有历史发布版本的完整索引,每个 tag 对应一次上线的代码与变更内容
  • 打包的代码一定包含 master 的全部提交(Jenkins 增加检查脚本保障)
  • 所有上线代码均经过 Code Review
  • 最小化 commit 在不同分支间的流动:仅有单测试分支时,整个流程只存在测试分支向 master 的一次合并

这套方案的核心取舍是:以 Git Flow 的双主干结构换取发布安全性,以 --ff-only 合并保证 master 的可追溯性,以 CR 门禁换取上线质量。对于单一生产版本、按窗口发布的团队,这是目前成本最低、风险最可控的路径。


最后修改于 2024-09-30