Git 多分支开发实践:彻底搞懂 Master、Dev、Feature、Hotfix

很多人会用 Git,但真正进入团队开发后,经常会遇到这些问题:

  • 为什么不能直接在 Master 上开发?
  • Dev 分支到底是干什么的?
  • Feature 分支什么时候创建?
  • Merge 和 Rebase 到底有什么区别?
  • IDEA 右键菜单里的各种操作对应什么 Git 命令?

本文通过一个完整项目案例,带你彻底理解 Git 多分支开发模型。


先看全局:一个项目是如何流转的

在开始之前,先记住下面这张图。

                                  发布
                                    │
                                    ▼

┌──────────────┐          ┌─────────────────┐
│ feature/*    │─────────▶│      dev        │
│ 功能开发      │ Merge    │   测试集成区     │
└──────────────┘          └─────────────────┘
                                   ▲
                                   │
                                   │ Merge
                                   │
                                   ▼
                         ┌─────────────────┐
                         │     master      │
                         │    线上版本      │
                         └─────────────────┘


同步代码:
master ───────▶ dev

线上修复:
master ───────▶ hotfix/* ───────▶ master

实际上:feature/* → dev → master,就已经覆盖了绝大多数团队开发场景。


为什么不要直接在 Master 上开发

很多新手项目是这样的:

master:A ── B ── C ── D ── E ── F

所有内容都往 Master 提交: Agent核心功能; Bug修复;实验代码

看起来很简单。

但实际上:

登录功能写崩 → 项目无法发布
实验代码提交 → 影响所有开发
线上Bug出现 → 无法快速定位版本
多人同时开发 → 冲突不断

因此实际项目都会引入分支隔离。核心思想:

开发归开发
测试归测试
线上归线上

互不影响。


各个分支到底负责什么

最推荐的小团队模型:

feature/* ---→ dev ---→ master
                ↑
             hotfix/*

职责如下:

分支 作用
master 永远保持可发布
dev 团队开发主线
feature/* 新功能开发
hotfix/* 紧急线上修复

理解成公司里的不同环境:

feature/* → 开发环境
dev       → 测试环境
master    → 生产环境

就非常容易理解。


一次完整开发流程

假设现在要开发 Agent 功能。整个流程其实只有四步。

Step1:从 Dev 创建feature功能分支

当前状态:

master ─────── A ───── B
dev    ─────── A ───── B

创建:

git checkout dev
git checkout -b feature/agent

结果:

master          A ───── B
dev             A ───── B
feature/agent   A ───── B

Step2:在 Feature 分支开发

所有代码都提交到功能分支。

feature/agent: A ───── B ───── C ───── D ───── E

期间不断:git add .; git commit; git push, 此时:

master          A ───── B
dev             A ───── B
feature/agent   A ───── B ───── C ───── D ───── E

不会影响任何人。

Step3:合并回 Dev

功能开发完成。

执行:

git checkout dev
git merge feature/agent

结果:

master: A ───── B
dev:    A ───── B ───── C ───── D ───── E

此时开始测试验证。

Step4:发布到 Master

测试通过后执行:

git checkout master
git merge dev

结果:

master:A ───── B ───── C ───── D ───── E
dev:   A ───── B ───── C ───── D ───── E

正式上线。整个生命周期:

feature/agent
       └────────→ dev
                   └────────→ master

建议在这个新章节里扩写以下 3种团队最常见的真实合并场景

如何同步别人代码

这是最容易搞混、也最容易踩坑的部分。

场景假设:你基于master分出了 dev 分支,你在 dev 上写了一个提交 C。此时,同事把他的代码 D 优先推到了 master。此时:

master:A ───── B ───── D (同事的最新提交)
dev   :A ───── B ───── C (你的本地提交)

此时你的 dev 分支落后了,想要把 master 上的新代码 D 同步进来,有两种方案。

方案一:Merge(合并)

核心逻辑:把 master 的新代码“拉”过来,和你的代码强行揉在一起,生成一个全新的“合并提交”。

执行

git checkout dev
git merge master

结果:

master:A ───── B ───── D
                        ╲
dev   :A ───── B ───── C ───── M (新生成的Merge合并提交)

特点

  • 绝对安全:纯粹的增量操作,完全不影响、不修改任何已经存在的历史提交。
  • 冲突一次搞定:哪怕 CD 有一万个冲突,也只需要在生成 M 提交时一次性解决。
  • 缺点:如果天天都这么干,Git 历史树会充斥着无数个无意义的 Merge branch... 节点,变成复杂的“麻花辫”。

方案二:Rebase(变基)

核心逻辑:把你的本地提交 C 先“拔出来”放在一边。把 dev 的地基直接换成 master 的最新状态 D,然后再把 C 重新“贴”上去(变成 C')。

执行

git checkout dev
git rebase master

结果:

master:A ───── B ───── D
                        ╲
dev   :A ───── B ───── D ───── C' (你的提交被重新应用在了 D 后面)

特点

  • 历史极度干净:强制抹平分支分叉,提交记录是一条完美的直线,像是一个人串行开发出来的一样。
  • 冲突需要耐心:如果是多笔提交进行 Rebase,Git 会按照提交顺序逐个应用,你可能需要反复、多次解决同一个地方的冲突。
  • 黄金铁律只能在自己的私有分支上进行! 如果你把已经推送到远端、别人也在用的公共分支拿来 Rebase,会导致同事的代码全部报废。

Merge 和 Rebase 怎么选

对比维度 git merge git rebase
适合场景 公共分支、多人协作分支(如 maindevelop 个人本地分支、特性(feature)分支
历史呈现 真实但复杂。保留完整的分支图表与交叉痕迹 干净且线性。抹平分叉,历史是一条直线
冲突处理 一次性解决。所有冲突在最后的 Merge 提交中统一解决 逐步解决。按提交顺序逐个解决,可能需要多次重复操作
安全性 极高。纯增量操作,任何时候都不会改写过去的历史 有风险。重写历史 Hash,严禁在公共分支上执行

📌 终极一句话口诀:

对外(公共分支/同步主干)用 Merge 尊重历史;对内(本地私有/提交 PR 前)用 Rebase 净化历史。

如何把代码合入主干(Push)

在本地把代码开发完毕,并且同步了别人的最新代码后,接下来就要把你的 dev 分支正式合回 master 主干。

合并前:

master:A ───── B ───── D
dev   :A ───── B ───── D ───── C'

在正规团队中,绝对不允许在本地直接 git merge。你必须走云端流程:

Pull Request / Merge Request

  1. 推送分支git push origin dev
  2. 发起申请:登录 GitHub/GitLab 网页,点击 Create Pull Request (PR),申请将 dev 合入 master
  3. 代码评审:邀请团队大佬进行 Code Review。
  4. 网页端一键合并:大佬通过后,在点击网页上的 Merge 按钮前,通常会有以下两种技术选项(由项目负责人根据团队规范选择):

Fast-Forward(普通/快进合并)

合并后(Fast-Forward):

master:A ───── B ───── D ───── C'
dev   :A ───── B ───── D ───── C'
  • 特点:主干指针直接“快进”指向你的最新提交,历史是一条直线。但如果删除了 dev 分支,后续就看不出这段代码曾是在独立分支上开发的。

Squash and merge (压缩合并)

一般推荐这个。
合并后(Squash):

master:A ───── B ───── D ───── C(你在dev上的所有碎提交被揉成了一个完美的C)
dev   :A ───── B ───── D ───── C1 ─── C2 ─── C3
  • 特点:把你在 dev 上的所有零碎提交(修错字、测Bug)打包压缩成一个干净完美的提交贴在 master 后面,主干历史极度整洁。

线上 Bug 如何修复(Hotfix)

假设线上登录功能突然崩溃。

很多新人会这样做:

dev
   ↓
修复
   ↓
master

这是错误的。

因为:

dev 上可能还有一堆没开发完的功能

正确流程:

master ─────→ hotfix/login-crash
                    │
                    │ 修复
                    ▼
              hotfix完成
                    │
                    ▼
master ─────────────┘
                    │
                    ▼
dev

完整链路:

master
    │
    └────→ hotfix/login-crash
                          │
                          └────→ master
                                      │
                                      └────→ dev

这样:

  • 线上立即恢复
  • 未完成功能不受影响
  • 开发节奏不会被打乱

个人项目最佳实践

对于个人项目。没必要照搬 GitFlow。

直接:feature/* ─────→ dev ─────→ master就够了。

例如:

feature/agent
feature/template
feature/search

全部开发完成后:

feature/*
      └────→ dev
              └────→ master

足以覆盖:独立开发 ;2~5人团队

IDEA 右键菜单速查

很多人天天看 JetBrains 系列的 IDEA / Android Studio / Pycharm菜单。
却不知道对应什么 Git 操作。以下是每个操作的含义解析:
此时:

  • 当前所在分支:fix/...
  • 鼠标右键点击的(选中分支):developer

操作名称 核心含义 具体作用与应用场景 对应 Git 命令 / 说明
Checkout 切换分支 切换到选中的 developer 分支,将工作区文件恢复到该分支状态。 git checkout developer 或 git switch developer
New Branch from... 从选中分支建新分支 以 developer 分支为起点,创建一个全新的本地分支并自动切换过去。 git checkout -b <新分支名> developer 或 git switch -c <新分支名> developer
Checkout and Rebase onto 'fix/...' 切换并变基 (选中分支移动) 先切换到 developer 分支,然后将 developer 分支上的新提交变基到 fix/... 之上。 👉 场景:修复完成,准备把主干代码挪到修复代码后面,保持线性历史。 git checkout developer git rebase fix/...
Rebase 'fix/...' onto 'developer' 变基到选中分支 (当前分支移动) 保持在当前 fix/... 分支,直接将 fix/... 上的新提交变基到 developer 之上。 👉 场景:开发中途,去拉取主干的最新代码并解决冲突。 git rebase developer (此时人已在 fix/... 分支)
Merge 'developer' into 'fix/...' 将选中分支合并到当前 传统的 Git 合并。将 developer 的代码合并进当前 fix/... 分支,通常会产生一个合并节点(Merge Commit)。 git merge developer (此时人已在 fix/... 分支)
Compare with... 与该分支对比 对比当前 fix/... 分支与选中的 developer 分支之间的代码和提交差异。 git diff fix/.....developer
Show Diff with Working Tree 与当前工作区对比 查看选中的 developer 分支与你当前本地工作区(未提交的修改)之间的差异。 git diff developer
Update 更新分支 从远程仓库拉取该分支的最新代码。若非当前分支,Git 只会在后台更新本地指针,不触发合并。 git fetch origin developer:developer
Push... 推送分支 将本地的 developer 分支提交推送到远程服务器(如 GitHub / GitLab)。 git push origin developer
Rename... 重命名分支 修改 developer 分支的名字。 git branch -m developer <新名称>
Delete 删除分支 删除本地的 developer 分支。如果包含未合并的代码,系统会报错拦截。 git branch -d developer (强删使用 -D)

重点说下这两个 Rebase(此时,“当前分支” = fix/...,“选中分支” = developer):

在 Git 术语中,Rebase A onto B 的意思是:“把 A 挪到 B 的后面”(A 的历史改变,B 保持不动)。因此:

  1. Checkout and Rebase onto 'fix/...'(将“选中分支”变基到“当前分支”)
    实际动作:Git 先帮你切换到 developer(选中分支),然后把 developer 上特有的新提交,切下来挪到 fix/...(当前分支)的最新提交后面。
    谁的历史变了:developer 分支。

  2. Rebase 'fix/...' onto 'developer'(将“当前分支”变基到“选中分支”)
    实际动作:不切换分支,直接把当前所在的 fix/...(当前分支)上的新提交,切下来挪到 developer(选中分支)的最新提交后面。
    谁的历史变了:fix/... 分支。

总结

如果只能记住一张图。

新功能开发:
feature/*
      └────────→ dev
                  └────────→ master


同步主分支:
master ───────────────→ dev

线上修复:
master ───→ hotfix/* ───→ master ───→ dev

一句话总结:Feature负责开发;Dev负责集成测试; Master负责线上发布; Hotfix负责紧急救火

最常用的命令其实也就五个:

Checkout → 切换分支

New Branch → 创建分支

Compare → 查看差异

Rebase → 同步代码

Merge → 合并代码
posted @ 2026-06-18 00:13  kingwzun  阅读(11)  评论(0)    收藏  举报