Git Flow是一种标准Git分支模型,由Vincent Driessen于2010年提出,他开发的插件git-flow可以自动化完成分支的创建、合并等工作,大大减轻了分支操作的工作量。在十几年前Git刚刚出现的时候是有意义的,当时SVN比较普及,人们不太懂如何使用Git。
但在十几年后的今天,由于Git Flow的结构过于繁琐和复杂,它完全放弃了rebase,分支结构错综复杂,即使有插件git-flow,但使用和维护起来的工作量仍然不小,不利于现如今的持续交付流程。
我们需要一种新的Git分支模型来适应现代化的开发需求,本文推荐由Fork的开发者提出的Lean Branching:⭐️ Lean Branching - a git branching model to keep clean history · Issue #1432 · fork-dev/TrackerWin
事实上,最开始的git-flow插件仓库已被废弃,有十几年没有更新:nvie/gitflow: Git extensions to provide high-level repository operations for Vincent Driessen’s branching model.
目前Git中默认安装的AVH版本的仓库也有好几年没有更新,且于2023被归档了:petervanderdoes/gitflow-avh: AVH Edition of the git extensions to provide high-level repository operations for Vincent Driessen’s branching model
虽然目前正在持续维护的CJS版本的仓库还在更新,但看Star量,已经没有那么多人在使用了:CJ-Systems/gitflow-cjs: CJS Edition of the git extensions to provide high-level repository operations for Vincent Driessen’s branching model
作者Vincent Driessen在他提出Git Flow的著名文章A successful Git branching model » nvie.com中于2020年补充道:“现如今的Web应用通常是持续交付的,不会回滚,你也不必支持在各处运行的多个软件版本”。“如果需要做软件的持续交付,我建议采用更简单的流程(比如GitHub flow),而不是试图将git-flow强加给你的团队”。我们需要找到适合自己工作流程的分支模型,Git Flow并不是万能药,使用与否应当自行掌握。
Fork的开发者Dan Pristupov也在一个Issue中表示,Git Flow已经过时,Fork将不再花大功夫继续改进维护这种工作流:[Enhancement] Gitflow: Rember my starting branch · Issue #1717 · fork-dev/TrackerWin
也有一些文章指出了Git Flow的不足,呼吁停止推荐它:Please stop recommending Git Flow! – George Stocker
这些迹象表明Git Flow已渐渐无法适应现代化的开发交付流程,我们需要灵活使用rebase来简化历史分支结构,让分支可以保持清晰的版本历史记录。但是rabase操作流程是Git中的高级操作,比较复杂和危险,因此开发者在Fork中支持了Lean Branching,通过一次点击,Fork可以自动化完成所有流程,大大降低了使用门槛。
本文将对Lean Branching做详细的介绍,并在Fork中结合的实际仓库示例来展示使用Lean Branching模型的开发流程。
1. 简要介绍
Lean Branching是Fork的开发者Dan Pristupov提出的一种保持干净历史的Git分支模型,官方介绍页面:⭐️ Lean Branching - a git branching model to keep clean history · Issue #1432 · fork-dev/TrackerWin
简要来说,Lean Branching的基础思想是,只有一个单独的开发分支main
,为每个功能创建一个单独的分支,使用rebase将你的更改与main
分支同步,并在最后合并回main
分支。
此思想与一篇Chris Manson的文章中的内容相似,有兴趣的话可以阅读一下:Git Good - The magic of keeping a clean Git history | Mainmatter
最后实现的分支效果图为:
分支结构非常简单,且历史开发记录非常清晰。
实现这一效果可能需要用到一些Git中比较高级,也比较危险的操作,例如rebase、force push with lease、hard reset,因此开发者在Fork中引入了一个sync
按钮来让Fork自动执行这些操作。
Lean Branching的目标是:
- 流程简单
- 默认情况下保持历史记录整洁
- 不引入命名规范。Fork可以使用
main
、develop
或master
。 - 对高级用户来说直观
- 容易向非开发人员解释
工作流程如下(以在main
分支下开发为例):
- 在
main
上开始一个分支 - 提交更改。尽可能频繁地与
main
同步(使用sync
操作),以最小化未来的冲突 - 当工作完成后,通过将其合并到
main
来完成分支
为了实现这个流程,Fork中在分支菜单中的提供了三个选项:
开始新分支(Start new branch)
在main
或origin/main
(取决于哪个是领先的)上创建并切换到新分支。
此处由于仓库中包含
develop
分支,因此新分支默认是在它的基础上创建,后面将展示如何修改。
同步活动分支(Sync active branch)
- 在远程跟踪分支上rebase(如果需要)
- 在
main
上进行变基(如果需要) - 使用强制推送(force push)将远程跟踪分支位置恢复到新位置。所以,如果它比分支落后两个提交,同步(sync)后仍然会落后两个提交。如果要同步这两个提交,需要用到最后一步的合并。
如果活动分支是main
,同步将简单地在其上变基origin/main
。
虽然Lean Branching只有活动分支,没有像Git Flow那样对几种不同功能的分支有强制命名,但一般还是按照标准命名规范,如特性分支为feature/xxxxx
。
完成活动分支(Finish active branch)
将当前分支合并到main
,但如果该分支只有一个提交,则使用快速前移(fast-forward)。
前提条件:main
必须与origin/main
保持同步。
这里的完成分支与git-flow类似,默认多个提交不使用fast-forward,但只有一个分支时,会使用这个功能,后面将展示如何修改这个选项,使得所有情况下都不使用fast-forward。
2. 仓库设置
在Fork中,可以对仓库进行设置来改变Lean Branching的默认行为。
在侧边栏右上角点击齿轮图标,或点击菜单栏的“Repository”,选择“Setting for This Repository…”,即可打开仓库设置。
在仓库设置中,关于Lean Branching的设置项有两个,一个是设置当前的主分支,当本地仓库中有develop
分支时,默认主分支就是develop
。不过由于Lean Branching分支模型中只有一个主分支,因此可以直接将develop
分支舍弃,设置主分支为main
。
另一个选项是设置合并时是否使用fast-forward,我们在Git Flow模型中介绍过,使用fast-forward可能会导致分支历史丢失,应当尽量避免。
虽然Fork的Lean Branching模型也会和git-flow一样,在一个分支中包含多个提交时,默认使用--no-ff
选项进行分支合并,但当一个分支仅包含一个提交时,默认采用fast-forward方式。如果我们想要保持主分支上只有合并的提交,没有其他分支的提交,保存所有的开发历史时,应当勾选“No fast-forward on merge”选项。
3. 一个完整功能的开发示例
3.1 开始新分支
以一个新功能feature_4
为例,在Branch菜单中点击“Start Branch on ‘main’…”,即可在主分支上创建一个新分支。
如果像这个例子一样想要开发一个新特性,分支名可以以feature/
为前缀,设置为feature/feature_4
,其他类型的分支同理,尽量在前面加一个分支类型,如hotfix/xxxxx
。
3.2 开发新特性
创建新分支后,即可在当前分支上进行新功能的开发,提交若干个Commit。
3.3 同步活动分支
点击Branch菜单中的“Sync ‘feature/feature_4’ (Rebase on main)”选项,Fork会自动化同步当前的活动分支。
点击sync选项时,Fork会自动将当前分支rebase到main
分支上,并进行force push
。不过这个例子中由于本地和远程的main
分支在开发新分支时都没有改动,因此同步前后效果不明显。下个例子中会展示在有改动时执行同步的效果。
3.4 完成活动分支
点击Branch菜单中的“Finish ‘feature/feature_4’ (Merge into ‘main’)…”选项,即可将活动分支合并到主分支中。
至此,我们使用Git的Lean Branching分支模型完成了一个完整功能的开发。
值得一提的是,Fork在完成一个分支时,为了安全,不会主动删除开发完成的分支,也不会自动执行Push操作。
如果确定这个特性已开发完成,且本地测试没有问题,可以手动删除该分支,并手动执行Push操作。
如果新建的分支是开发分支或热修复分支,可以在Push前手动添加版本号Tag。
点击侧边栏develop
分支右边的小眼睛按钮,可以屏蔽它的显示,这时候可以看到Lean Branching分支模型的简洁分支结构和提交历史。
4. 本地和远程不同步时的示例
当多人协作开发同一个项目时,难免会出现本地更改和远程不同步的情况。
例如我们在第一天拉取了远程的最新代码,在此基础上新建了一个分支开始一个新功能的开发,三天后,新功能开发完成,我们想要将这个新功能加入主分支中。
但这三天之内,远程仓库已经做了很多更改,本地仓库已经落后与远程,Fetch之后可能如下图中的情况:
可见我们开发的新功能feature_5
是基于以前的版本,此时执行同步(sync),可以将这个分支上的修改rebase到最新的修改上。
如果执行同步时出现冲突,需要手动解决:
可以使用内置的冲突解决编辑器,也可以配置外置编辑器,以VS Code为例,点击左上角菜单栏“File-Preferences…”打开设置,在设置项“Integration”中选择编辑器类型并配置路径,重启Fork后生效。
点击Merge解决冲突。
根据提示进行冲突解决。
VS Code中解决冲突完成后需要“Ctrl+S”保存。
点击Stage后,点击“Continue Rebase”继续Sync流程。
如果本地的开发分支中的多个提交均与远程仓库中的新提交产生冲突,需要一一解决。
一般情况下,我们应该尽可能频繁地使用Sync功能与
main
分支同步,以尽量减少未来可能出现的冲突,此处的示例就是由于在开发过程中没有经常同步更改,导致后续需要解决的冲突比较多,是一种较为极端的情况。实际上,新分支与主分支同步较为频繁时,一般不会出现这种情况。
直到本地分支所有提交的冲突都解决完成,再次点击“Continue Rebase”后即可完成同步操作。
可以看到完成同步后,本地落后的开发分支中的所有更改被rebase到了最新的分支上,这样就相当于这个feature_5
的新功能是在最新分支的基础上更改的,维持了分支结构的简洁。
此时,点击完成活动分支,即可完成这个新特性与最新更改之间的合并。
至此,我们使用Git的Lean Branching分支模型完成了一个完整功能的开发,并在与远程仓库有冲突时完成了同步流程。
测试无误后,可以将特性分支删除,并执行Push操作,最终将本地的更改同步到远程仓库。
至此,Lean Branching分支模型已介绍完成。
可以看到,与Git Flow相比,采用Lean Branching分支模型后,提交历史非常简洁清晰,且所有提交历史都得到保留,便于追溯,且有利于后续的维护。
由此可见,Lean Branching模型更能适合现代化的项目开发流程,推荐使用。
本文链接: https://hanqingjiang.com/2025/09/03/20250903_leanBranching/
版权声明: 本作品采用 CC BY-NC-SA 4.0 进行许可。转载请注明出处!
