概要
Git Flow将branch分成2个主要分支和3个临时的辅助分支
-
master: 永远处在即将发布(production-ready)状态
-
develop: 最新的开发状态
-
feature/*: 开发新功能的分支, 基于 develop, 完成后 merge 回 develop
-
release/*: 准备要发布版本的分支, 用来修复 bug. 基于 develop, 完成后 merge 回 develop 和 master
-
hotfix/*: 修复 master 上的问题, 等不及 release 版本就必须马上上线. 基于 master, 完成后 merge 回 master 和 develop
使用工具
git-flow是一个辅助使用git flow模式的工具。
分别体验了以下git-flow和git-flow-avh,nvie的git-flow上一次更新已经是7年前了,好多bug没有改,好多功能也没有完善。petervanderdoes的gitflow-avh的功能就相对完善一些,帮助文档也更详细一些。所以使用git-flow-avh来辅助使用git flow模式
安装
官网链接:https://github.com/petervanderdoes/gitflow-avh/wiki/Installation(好像已不维护了但不影响使用)
Mac 需要独立安装
brew install git-flow-avh
Windows 已经包含在 git.exe 安装包里了,无需额外安装
初始化
# 如果已经初始化过了,-f 可以强制重新初始化
git flow init [-f]
# 选择生产分支,开发分支及其他临时分支的前缀
Which branch should be used for bringing forth production releases?
- develop
- master
Branch name for production releases: [master]
Which branch should be used for integration of the "next release"?
- develop
Branch name for "next release" development: [develop]
How to name your supporting branch prefixes?
Feature branches? [feature/]
Release branches? [release/]
Hotfix branches? [hotfix/]
Support branches? [support/]
Version tag prefix? []
开发
# 从develop分支创建并切换到功能分支feature/<name>,<base>可以指定commit,必须是develop分支上的commit
git flow feature start <name> [<base>]
# 提交开发内容
git add/commit
# 提交分支到远程
git flow feature publish <name>
# 切换到,并拉取feature分支
git flow feature track <name>
# 本地合并feature/<name>分支到develop分支,并删除feature/<name>分支
git flow feature finish -F --push <name>
# 合并后其他开发同学需要删除本地的feature分支
# 新版本会在finish后自动将本地的分支和远程的分支都清理,无需额外处理了
git flow feature delete -f <name>
# 在本地删除远程feature分支(服务器上的远程分支已经删除,但是本地git branch -r还是可以看到)
git branch -r -d origin/feature/<name>
备注
git flow feature finish -F --push <name> 完成的操作
Summary of actions:
- The feature branch 'feature/f9' was merged into 'develop'
- Feature branch 'feature/f9' has been locally deleted; it has been remotely deleted from 'origin'
- You are now on branch 'develop'
git flow feature finish 帮助
$ git flow feature finish --help
usage: git flow feature finish [-h] [-F] [-r] [-p] [-k] [-D] [-S] [--no-ff] <name|nameprefix>
Finish feature <name>
-h, --help Show this help
--showcommands Show git commands while executing them
-F, --[no]fetch Fetch from origin before performing finish
-r, --[no]rebase Rebase before merging
-p, --[no]preserve-merges
Preserve merges while rebasing
--[no]push Push to origin after performing finish
-k, --[no]keep Keep branch after performing finish
--keepremote Keep the remote branch
--keeplocal Keep the local branch
-D, --[no]force_delete
Force delete feature branch after finish
-S, --[no]squash Squash feature during merge
--no-ff Never fast-forward during the merge
上线
# 从develop分支新建release分支: release/<release>,<base>可以指定commit,必须是develop分支上的commease> [<base>]
# 提交release分支
git flow release publish <release>
# 切换到,并拉取release分支
git flow release track <release>
# 进行测试和bug修复
git add/commit/push
git rebase 和 merge 合并知识
rebase 变基的特点是切换到当前分支,然后把自己的继承链迁移到需要变基的最新分支上去,此时可能出现一些冲突,产生新的初始合并点,这样新开分支的迭代过程也可以详细地记录在合并分支上去,但是合并分支的话,则并不在
什么时候需要用 Rebase?
适合使用 Rebase 的场景:
-
个人开发分支:
-
在开发一个功能时,可以使用
rebase
将自己的分支基于主分支最新状态,避免合并冲突。 -
示例:
-
-
在推送代码之前整理提交历史:
-
提交前使用
git rebase -i
清理不必要的提交,例如删除测试提交、实验性提交等。
-
-
协作开发时保持代码最新:
-
和团队成员协作时,先
pull --rebase
远程分支,让自己的更改基于最新代码。
-
示例:
git pull --rebase origin main
-
清理历史记录,构建开源项目:
-
对于需要发布的分支,Rebase 可以让整个项目的提交历史更清晰,利于用户理解和使用。
-
Rebase 可以将当前特性分支基于 master
最新提交,减少合并时的冲突
原因:
当你在一个 feature
分支上开发时,master
分支的代码可能已经更新(比如团队其他成员提交了新的更改)。如果你直接尝试将 feature
合并到 master
,可能会遇到多个冲突。
而 rebase
是通过将你的 feature
分支重新“基于” master
的最新提交,使得你的分支看起来像是从最新的 master
开始开发的。
效果:
-
避免历史分叉,提交历史看起来更干净。
-
提交记录像是直接基于最新的
master
开发的,不会带来无意义的分支分叉。 -
合并时冲突减少,因为
feature
分支已经包含了master
的最新内容。
代码示例:
假设当前分支情况如下:
master: A --- B --- C
feature: D --- E --- F
此时有人在 master
提交了 G
:
master: A --- B --- C --- G
feature: D --- E --- F
如果直接合并:
git checkout master
git merge feature
结果是:
D --- E --- F
/ \
A --- B --- C ----------- M (merge commit)
如果先使用 rebase
:
git checkout feature
git rebase master
结果是:
master: A --- B --- C --- G
feature: D' --- E' --- F'
然后合并到 master
:
git checkout master
git merge feature
历史记录看起来像是:
master: A --- B --- C --- G --- D' --- E' --- F'
Rebase 的冲突时机
-
Rebase 的本质是 逐个提交重新应用到目标分支的最新状态上。
-
因此,冲突可能发生在 将每个提交重新应用的过程中。
冲突场景:
假设我们有以下分支:
plaintext复制代码master: A --- B --- C
feature1: D --- E
在 rebase
操作中,feature1
的提交会逐一应用到 C
之后:
-
首先应用
D
,生成D'
。 -
然后应用
E
,生成E'
。
如果 D
的修改与 C
的代码有冲突,冲突会在 D
应用到 C
时发生。
Rebase 的冲突点:
-
D
合并到C
时(生成D'
)。 -
E
合并到D'
时(生成E'
)。
冲突原因:
-
D
或E
的更改与master
最新提交(C
)之间存在代码上的矛盾。
Rebase 和 Merge 冲突的比较两者冲突的对比
特性 | Rebase | Merge |
冲突时机 | 每个提交在被重新应用时可能产生冲突。 | 在所有改动合并时(创建合并提交时)可能产生冲突。 |
冲突复杂度 | 可能多次出现冲突(逐一提交应用)。 | 只需解决一次冲突(合并整个分支时)。 |
冲突原因 | 每个提交的更改与目标分支的最新状态发生矛盾。 | 两个分支的所有改动之间有矛盾。 |
解决冲突的步骤 | 修复冲突后,逐一继续 Rebase。 | 修复冲突后完成合并提交。 |
适用场景 | 历史需要线性化,适合整理个人分支。 | 需要保留完整分支轨迹,适合公共分支或团队协作场景。 |
4. 冲突的处理方式
-
Rebase 的冲突解决更细粒度,因为它会逐一重新应用每个提交。如果提交很多且有冲突,会比较耗时。
-
Merge 的冲突解决更集中,因为所有改动会一次性合并到一起,只需解决一次冲突。
5. 为什么冲突出现的位置不同?
这是由两者的合并方式决定的:
-
Rebase 是逐步将每个提交重新应用到目标分支上,每次应用都需要检查是否与目标分支的代码冲突。
-
Merge 是直接将整个分支合并到目标分支,一次性处理所有冲突。
总结:冲突的核心差异
-
Rebase 冲突:发生在每个提交应用到目标分支的过程中,冲突粒度较小但可能多次出现。
-
Merge 冲突:发生在两个分支合并的整体过程中,冲突粒度较大但只出现一次。
两者的冲突处理并没有本质的优劣,关键是根据场景选择合适的合并策略:
-
选择 Rebase:当需要整理历史、保持线性记录时。
-
选择 Merge:当需要保留分支结构、避免篡改历史时。