admin管理员组

文章数量:1028874

【Git#3】分支管理下的分支策略

一、分支管理策略

通常在合并分支时,一般情况下Git会采用 Fast forward 模式。还记得如果我们采用 Fast forward 模式之后,形成的合并结果是什么呢?

在这种 Fast forward 模式下,删除分支后,查看分支历史时,会丢掉分支信息,看不出来最新提交到底是 merge 进来的还是正常提交的。

但在合并冲突部分,我们也看到通过解决冲突问题,会再进行一次新的提交,得到的最终状态为

那么这就不是 Fast forward 模式了,这样的好处是,从分支历史上就可以看出分支信息。

  • 例如:上面已经删除了在合并冲突部分创建的 dev1 分支,但依旧能看到 master 其实是由其他分支合并得到,如下:
代码语言:javascript代码运行次数:0运行复制
lighthouse@VM-8-10-ubuntu:gitcode$ git log --graph --pretty=oneline --abbrev-commit
*   cb7ce27 (HEAD -> master) merge book
|\  
| * da3c3b1 modify book
* | fc26892 modify book
|/  

Git 支持我们强制禁用 Fast forward 模式,那么就会在 merge 时生成一个新的 commit ,这样从分支历史上就可以看出分支信息。

下面我们实战一下 --no-ff 方式的 git merge。首先,创建新的分支 dev2,并切换至新的分支

代码语言:javascript代码运行次数:0运行复制
lighthouse@VM-8-10-ubuntu:gitcode$ git checkout -b dev2
Switched to a new branch 'dev2'

修改 book 文件,并且提交一个新的 commit

代码语言:javascript代码运行次数:0运行复制
lighthouse@VM-8-10-ubuntu:gitcode$ cat book
Hello Island1314
Hello World
hello version1
hello version2
hello version3
write bbb for new branch
a,b,c,d
lighthouse@VM-8-10-ubuntu:gitcode$ git add .
lighthouse@VM-8-10-ubuntu:gitcode$ git commit -m "modify Readme"
[dev2 2bd7b8b] modify Readme
 1 file changed, 1 insertion(+)

切换 master 分支,进行合并

代码语言:javascript代码运行次数:0运行复制
lighthouse@VM-8-10-ubuntu:gitcode$ git checkout master
Switched to branch 'master'
lighthouse@VM-8-10-ubuntu:gitcode$ git merge --no-ff -m "merge with no-ff" dev2
Merge made by the 'ort' strategy.
 book | 1 +
 1 file changed, 1 insertion(+)
lighthouse@VM-8-10-ubuntu:gitcode$ cat book
Hello Island1314
Hello World
hello version1
hello version2
hello version3
write bbb for new branch
a,b,c,d

请注意 --no-ff 参数,表示禁用 Fast forward 模式。禁用 Fast forward 模式后合并会创建一个新的 commit,所以加上-m 参数,把描述写进去。

合并后,查看分支历史:

代码语言:javascript代码运行次数:0运行复制
lighthouse@VM-8-10-ubuntu:gitcode$ git log --graph --pretty=oneline --abbrev-commit
*   ac37cfb (HEAD -> master) merge with no-ff
|\  
| * 2bd7b8b (dev2) modify Readme
|/  
*   cb7ce27 merge book
|\  
| * da3c3b1 modify book
* | fc26892 modify book
|/  
* 33a5368 modify book

可以看到,不使用 Fast forward 模式,merge 就像如下:

image-20250408202508056

所以在合并分支时,加上 --no-ff 参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而 fast forward 合并就看不出来曾经做过合并。

二、分支策略

在实际开发中,我们应该按照几个基本原则进行分支管理:

  1. 首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
  2. 那在哪干活呢?干活都在dev分支上
  3. 也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在 master 分支发布1.0版本;

你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了

所以,团队合作的分支看起来就像如下这样:

image-20250408202752871

三、六种合并策略

1. 合并策略全景图
2. 六大合并策略详解
① Fast Forward(快进合并)
  • 触发条件:目标分支没有新提交

命令示例

示例1:

代码语言:javascript代码运行次数:0运行复制
git merge --ff-only dev  # 强制仅快进合并

示例2:

代码语言:javascript代码运行次数:0运行复制
# 强制创建合并提交(即使可以快进)
git merge --no-ff feature/login

# 查看合并后的线性历史
git log --graph --oneline --decorate

示例3:错误演示

代码语言:javascript代码运行次数:0运行复制
# 错误:在已提交的主分支使用快进合并导致历史混乱
git checkout main
git merge --ff-only hotfix  # 若main有新提交则会失败
  • 图示
  • 特点
    • 线性历史
    • 无合并提交
    • 适用于临时特性分支
② Recursive(递归合并)

选项参数

作用描述

适用场景

-X patience

改进差异比对算法

复杂代码重构合并

-X ignore-space

忽略空格变化

跨平台开发合并

-X renormalize

统一行尾风格

混合Windows/Linux环境

-X diff-algorithm=histogram

更准确的历史分析

大型Java项目合并

  • 触发条件:存在分叉提交且需三方合并

命令示例

代码语言:javascript代码运行次数:0运行复制
 git merge -s recursive -X patience dev  # 使用特定差异算法
  • 图示
  • 特点
    • 自动处理多个共同祖先
    • 产生合并提交
    • 默认策略(占 Git 合并的 70%+)
③ Ours/Theirs(选择性合并)
  • 触发条件:需要强制保留特定分支内容

命令示例

示例1:使用规范

代码语言:javascript代码运行次数:0运行复制
# 正确流程示例(架构迁移场景):
git checkout new-arch
git merge -s ours old-arch    # 保留新架构
git checkout old-arch
git merge new-arch            # 同步代码但保留旧架构

示例2:危险操作告警

代码语言:javascript代码运行次数:0运行复制
# 错误示例:直接覆盖生产分支
git checkout production
git merge -X theirs staging  # 可能导致生产数据丢失!
  • 图示
  • 特点
    • 人工指定冲突解决方案
    • 常用于保留分支架构
    • 高风险操作(可能覆盖代码)
④ Octopus(章鱼合并)

触发条件:同时合并多个分支

命令示例

代码语言:javascript代码运行次数:0运行复制
git merge dev feat hotfix  # 一次性合并三个分支

图示

  • 特点
    • 仅限无冲突合并
    • 常用于 CI/CD 流水线
    • 历史记录最简洁
⑤ Subtree(子树合并)

Subtree

Submodule

存储方式

代码直接入库

引用外部仓库

历史追踪

完整保留

仅记录引用点

修改流程

直接修改+推送

进入子模块操作

适用场景

频繁修改的组件

稳定的第三方依赖

触发条件:合并外部仓库到子目录

命令示例

代码语言:javascript代码运行次数:0运行复制
git merge -s subtree --allow-unrelated-histories external-repo

图示

  • 特点
    • 保留外部仓库独立历史
    • 自动处理路径冲突
    • 适合组件化开发
⑥ Resolve(解决合并)

触发条件:简单分叉合并(Git 早期版本)

命令示例

代码语言:javascript代码运行次数:0运行复制
git merge -s resolve legacy-branch

图示

  • 特点
    • 仅处理单共同祖先
    • 比 recursive 更快
    • 逐渐被淘汰

3. 策略对比矩阵

策略

合并类型

冲突处理

历史记录

适用场景

风险等级

Fast Forward

线性移动

无冲突

完全线性

短期特性分支合并

Recursive

三方合并

自动+手动

合并提交

标准分支合并

⭐⭐

Ours/Theirs

选择性覆盖

强制解决

隐藏分叉

保留分支结构

⭐⭐⭐⭐

Octopus

多分支合并

必须无冲突

单点聚合

批量合并已验证分支

⭐⭐

Subtree

目录级合并

路径自动处理

独立子历史

第三方库集成

⭐⭐⭐

Resolve

简单三方合并

手动解决

合并提交

简单分叉合并(旧版本兼容)

⭐⭐


4. 实战场景推荐
  1. 功能开发Recursive(默认) + --no-ff 保留合并痕迹
  2. 紧急修复Fast Forward 快速上线
  3. 架构迁移Ours 策略保留新架构
  4. 多特性发布Octopus 一次合并多个已验证分支
  5. 组件更新Subtree 管理子仓库
  6. 遗留系统Resolve 处理简单合并

5. 高级调试技巧
代码语言:javascript代码运行次数:0运行复制
# 查看可用的合并策略
git merge -s help

# 显示合并细节(调试用)
git merge --verbose --stat -m "合并日志"

# 分析合并基准
git merge-base --all master dev

# 可视化合并过程
git mergetool -t meld

分支治理规范

  1. 黄金法则:main分支必须使用--no-ff合并
  2. 权限控制:保护分支禁止使用theirs策略
  3. 合并检查清单
    • ✅ 代码评审完成
    • ✅ CI流水线通过
    • ✅ 文档同步更新
    • ✅ 兼容性测试报告

合并策略决策树

【Git#3】分支管理下的分支策略

一、分支管理策略

通常在合并分支时,一般情况下Git会采用 Fast forward 模式。还记得如果我们采用 Fast forward 模式之后,形成的合并结果是什么呢?

在这种 Fast forward 模式下,删除分支后,查看分支历史时,会丢掉分支信息,看不出来最新提交到底是 merge 进来的还是正常提交的。

但在合并冲突部分,我们也看到通过解决冲突问题,会再进行一次新的提交,得到的最终状态为

那么这就不是 Fast forward 模式了,这样的好处是,从分支历史上就可以看出分支信息。

  • 例如:上面已经删除了在合并冲突部分创建的 dev1 分支,但依旧能看到 master 其实是由其他分支合并得到,如下:
代码语言:javascript代码运行次数:0运行复制
lighthouse@VM-8-10-ubuntu:gitcode$ git log --graph --pretty=oneline --abbrev-commit
*   cb7ce27 (HEAD -> master) merge book
|\  
| * da3c3b1 modify book
* | fc26892 modify book
|/  

Git 支持我们强制禁用 Fast forward 模式,那么就会在 merge 时生成一个新的 commit ,这样从分支历史上就可以看出分支信息。

下面我们实战一下 --no-ff 方式的 git merge。首先,创建新的分支 dev2,并切换至新的分支

代码语言:javascript代码运行次数:0运行复制
lighthouse@VM-8-10-ubuntu:gitcode$ git checkout -b dev2
Switched to a new branch 'dev2'

修改 book 文件,并且提交一个新的 commit

代码语言:javascript代码运行次数:0运行复制
lighthouse@VM-8-10-ubuntu:gitcode$ cat book
Hello Island1314
Hello World
hello version1
hello version2
hello version3
write bbb for new branch
a,b,c,d
lighthouse@VM-8-10-ubuntu:gitcode$ git add .
lighthouse@VM-8-10-ubuntu:gitcode$ git commit -m "modify Readme"
[dev2 2bd7b8b] modify Readme
 1 file changed, 1 insertion(+)

切换 master 分支,进行合并

代码语言:javascript代码运行次数:0运行复制
lighthouse@VM-8-10-ubuntu:gitcode$ git checkout master
Switched to branch 'master'
lighthouse@VM-8-10-ubuntu:gitcode$ git merge --no-ff -m "merge with no-ff" dev2
Merge made by the 'ort' strategy.
 book | 1 +
 1 file changed, 1 insertion(+)
lighthouse@VM-8-10-ubuntu:gitcode$ cat book
Hello Island1314
Hello World
hello version1
hello version2
hello version3
write bbb for new branch
a,b,c,d

请注意 --no-ff 参数,表示禁用 Fast forward 模式。禁用 Fast forward 模式后合并会创建一个新的 commit,所以加上-m 参数,把描述写进去。

合并后,查看分支历史:

代码语言:javascript代码运行次数:0运行复制
lighthouse@VM-8-10-ubuntu:gitcode$ git log --graph --pretty=oneline --abbrev-commit
*   ac37cfb (HEAD -> master) merge with no-ff
|\  
| * 2bd7b8b (dev2) modify Readme
|/  
*   cb7ce27 merge book
|\  
| * da3c3b1 modify book
* | fc26892 modify book
|/  
* 33a5368 modify book

可以看到,不使用 Fast forward 模式,merge 就像如下:

image-20250408202508056

所以在合并分支时,加上 --no-ff 参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而 fast forward 合并就看不出来曾经做过合并。

二、分支策略

在实际开发中,我们应该按照几个基本原则进行分支管理:

  1. 首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
  2. 那在哪干活呢?干活都在dev分支上
  3. 也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在 master 分支发布1.0版本;

你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了

所以,团队合作的分支看起来就像如下这样:

image-20250408202752871

三、六种合并策略

1. 合并策略全景图
2. 六大合并策略详解
① Fast Forward(快进合并)
  • 触发条件:目标分支没有新提交

命令示例

示例1:

代码语言:javascript代码运行次数:0运行复制
git merge --ff-only dev  # 强制仅快进合并

示例2:

代码语言:javascript代码运行次数:0运行复制
# 强制创建合并提交(即使可以快进)
git merge --no-ff feature/login

# 查看合并后的线性历史
git log --graph --oneline --decorate

示例3:错误演示

代码语言:javascript代码运行次数:0运行复制
# 错误:在已提交的主分支使用快进合并导致历史混乱
git checkout main
git merge --ff-only hotfix  # 若main有新提交则会失败
  • 图示
  • 特点
    • 线性历史
    • 无合并提交
    • 适用于临时特性分支
② Recursive(递归合并)

选项参数

作用描述

适用场景

-X patience

改进差异比对算法

复杂代码重构合并

-X ignore-space

忽略空格变化

跨平台开发合并

-X renormalize

统一行尾风格

混合Windows/Linux环境

-X diff-algorithm=histogram

更准确的历史分析

大型Java项目合并

  • 触发条件:存在分叉提交且需三方合并

命令示例

代码语言:javascript代码运行次数:0运行复制
 git merge -s recursive -X patience dev  # 使用特定差异算法
  • 图示
  • 特点
    • 自动处理多个共同祖先
    • 产生合并提交
    • 默认策略(占 Git 合并的 70%+)
③ Ours/Theirs(选择性合并)
  • 触发条件:需要强制保留特定分支内容

命令示例

示例1:使用规范

代码语言:javascript代码运行次数:0运行复制
# 正确流程示例(架构迁移场景):
git checkout new-arch
git merge -s ours old-arch    # 保留新架构
git checkout old-arch
git merge new-arch            # 同步代码但保留旧架构

示例2:危险操作告警

代码语言:javascript代码运行次数:0运行复制
# 错误示例:直接覆盖生产分支
git checkout production
git merge -X theirs staging  # 可能导致生产数据丢失!
  • 图示
  • 特点
    • 人工指定冲突解决方案
    • 常用于保留分支架构
    • 高风险操作(可能覆盖代码)
④ Octopus(章鱼合并)

触发条件:同时合并多个分支

命令示例

代码语言:javascript代码运行次数:0运行复制
git merge dev feat hotfix  # 一次性合并三个分支

图示

  • 特点
    • 仅限无冲突合并
    • 常用于 CI/CD 流水线
    • 历史记录最简洁
⑤ Subtree(子树合并)

Subtree

Submodule

存储方式

代码直接入库

引用外部仓库

历史追踪

完整保留

仅记录引用点

修改流程

直接修改+推送

进入子模块操作

适用场景

频繁修改的组件

稳定的第三方依赖

触发条件:合并外部仓库到子目录

命令示例

代码语言:javascript代码运行次数:0运行复制
git merge -s subtree --allow-unrelated-histories external-repo

图示

  • 特点
    • 保留外部仓库独立历史
    • 自动处理路径冲突
    • 适合组件化开发
⑥ Resolve(解决合并)

触发条件:简单分叉合并(Git 早期版本)

命令示例

代码语言:javascript代码运行次数:0运行复制
git merge -s resolve legacy-branch

图示

  • 特点
    • 仅处理单共同祖先
    • 比 recursive 更快
    • 逐渐被淘汰

3. 策略对比矩阵

策略

合并类型

冲突处理

历史记录

适用场景

风险等级

Fast Forward

线性移动

无冲突

完全线性

短期特性分支合并

Recursive

三方合并

自动+手动

合并提交

标准分支合并

⭐⭐

Ours/Theirs

选择性覆盖

强制解决

隐藏分叉

保留分支结构

⭐⭐⭐⭐

Octopus

多分支合并

必须无冲突

单点聚合

批量合并已验证分支

⭐⭐

Subtree

目录级合并

路径自动处理

独立子历史

第三方库集成

⭐⭐⭐

Resolve

简单三方合并

手动解决

合并提交

简单分叉合并(旧版本兼容)

⭐⭐


4. 实战场景推荐
  1. 功能开发Recursive(默认) + --no-ff 保留合并痕迹
  2. 紧急修复Fast Forward 快速上线
  3. 架构迁移Ours 策略保留新架构
  4. 多特性发布Octopus 一次合并多个已验证分支
  5. 组件更新Subtree 管理子仓库
  6. 遗留系统Resolve 处理简单合并

5. 高级调试技巧
代码语言:javascript代码运行次数:0运行复制
# 查看可用的合并策略
git merge -s help

# 显示合并细节(调试用)
git merge --verbose --stat -m "合并日志"

# 分析合并基准
git merge-base --all master dev

# 可视化合并过程
git mergetool -t meld

分支治理规范

  1. 黄金法则:main分支必须使用--no-ff合并
  2. 权限控制:保护分支禁止使用theirs策略
  3. 合并检查清单
    • ✅ 代码评审完成
    • ✅ CI流水线通过
    • ✅ 文档同步更新
    • ✅ 兼容性测试报告

合并策略决策树

本文标签: Git3分支管理下的分支策略