2、版本控制基础:Git核心概念(分支、合并、冲突解决),Git Flow与Trunk Based开发模式对比

2.1 分支:Git 的灵魂所在

说实话,我刚入行那会儿,对分支的理解特别肤浅。觉得分支不就是复制一份代码嘛,有啥好学的?直到有一次,我在一个项目里直接往 master 上 push 代码,结果把同事正在调试的功能给冲了……嗯,那次教训挺深刻的。

分支的本质,其实就是一个可移动的指针。每次你提交代码,这个指针就往前挪一步。我习惯把分支想象成「平行宇宙」——每个分支里都在发生不同的故事,但最终它们要合并回主时间线。

核心要点:

  • 主分支(main/master):生产环境的代码,原则上不允许直接修改
  • 功能分支(feature):开发新功能时创建,开发完合并回主分支
  • 修复分支(hotfix):线上出 bug 时紧急创建,修完立刻合并

2.2 合并:把平行宇宙拉回正轨

合并说白了,就是把两个分支的改动拼到一起。Git 提供了两种合并方式,我分别说说我的使用感受。

2.2.1 Fast-Forward 合并

这种情况最理想。你想想看,如果主分支在你创建功能分支后一直没动过,那合并就只是把指针往前推一下,没有新提交产生。干净利落。

# 当前在 main 分支
git merge feature/login
# 如果 feature/login 是基于 main 的最新提交创建的
# Git 会直接移动 main 的指针到 feature/login 的位置

2.2.2 Three-Way 合并

大多数情况是这种。主分支和你自己的分支都做了修改,Git 需要找一个「共同祖先」,然后对比两边的差异,生成一个新的合并提交。

我的小建议:合并前先执行 git fetch 拉取最新代码,再用 git log --oneline --graph 看看分支拓扑图。我每次合并前都会看一眼这个图,心里就有底了。

2.3 冲突解决:Git 的「吵架」现场

冲突这东西,躲是躲不掉的。我记得有一次,我和另一个同事同时修改了同一个配置文件,结果合并时爆了 30 多个冲突……那天下午我啥也没干,就坐在那一个一个解。

冲突长什么样?Git 会在文件里插入这样的标记:

<<<<<<< HEAD
const API_URL = 'https://api.prod.com';
=======
const API_URL = 'https://api.dev.com';
>>>>>>> feature/debug

上面是当前分支的内容,下面是你要合并进来的内容。你需要手动决定保留哪个,或者两个都保留。

避坑指南:我曾经犯过一个低级错误——解完冲突后忘了删掉 <<<<<<<======= 这些标记,结果代码编译直接挂了。所以解完冲突后,一定要用 grep -r "<<<<<<" . 扫一遍项目,确保没有残留。

2.4 Git Flow vs Trunk Based:两种开发哲学的碰撞

这两种模式我都用过,各有各的适用场景。我直接拿表格对比一下,这样更直观。

对比维度 Git Flow Trunk Based
分支数量 多(master、develop、feature、release、hotfix) 少(主要就一个主分支)
发布频率 低(通常按版本发布) 高(每天多次甚至持续发布)
冲突概率 低(分支隔离时间长) 高(频繁合并,冲突多)
适合团队 大型团队、传统项目 小型团队、敏捷团队
学习成本 高(分支模型复杂) 低(简单直接)

2.4.1 Git Flow:规矩多,但稳

Git Flow 是我最早接触的工作流。它把分支分得很细:develop 是日常开发分支,release 是预发布分支,hotfix 是紧急修复分支。每个分支都有明确的职责。

说实话,这种模式在管理大型项目时确实好用。我记得在做一个电商平台时,我们同时有 3 个版本在开发:v2.0 在测试,v2.1 在开发,v1.9 还在修 bug。Git Flow 的分支模型让这一切井井有条。

Git Flow 的典型流程:

  1. develop 创建 feature/login
  2. 开发完成后合并回 develop
  3. 准备发布时,从 develop 创建 release/2.0
  4. release 分支上只修 bug,不加新功能
  5. 测试通过后,合并到 masterdevelop
  6. 线上出 bug 时,从 master 创建 hotfix/2.0.1

2.4.2 Trunk Based:简单粗暴,但快

Trunk Based 就简单多了。所有开发者都在主分支上工作,或者最多创建短期存在的功能分支(通常不超过两天)。说白了,就是「频繁提交、频繁合并」。

我现在的团队就用 Trunk Based。每天每个人至少往主分支合并 2-3 次。刚开始大家都不适应,觉得太频繁了。但习惯了之后,你会发现冲突反而少了——因为每次合并的改动量都很小,解起来特别快。

我的经验:Trunk Based 要想玩得转,必须搭配特性开关(Feature Toggle)。比如你开发一个新功能,但还没做完,就用开关把它藏起来。这样即使代码合并到主分支,也不会影响线上用户。我见过太多团队因为不用特性开关,结果 Trunk Based 搞得一团糟。

2.5 到底选哪个?

这个问题没有标准答案。我个人的建议是:

  • 如果你的团队超过 20 人,或者项目需要同时维护多个版本,Git Flow 更合适
  • 如果你的团队在 10 人以内,追求快速迭代,Trunk Based 是更好的选择
  • 如果你刚开始用 Git,先从 Trunk Based 入手,等熟练了再尝试 Git Flow

嗯,版本控制这东西,说白了就是「规矩」和「效率」的平衡。找到适合自己团队的节奏,比盲目追求某种「最佳实践」重要得多。