Git分支管理之分支创建、切换和合并操作详解

2026-06-27编程代码26323

本文会从分支的本质讲起,把分支的前世今生画成时间线,让你彻底看懂 HEAD、分支指针、合并提交到底是什么,然后手把手教你创建、切换、合并、删除分支等操作,希望对大家有所帮助

目录
  • 前言
  • 一、分支是什么:从时间线讲起
    • 1.1 一个生活中的类比
    • 1.2 Git 的分支本质
    • 1.3 创建分支后,时间线长这样
    • 1.4 HEAD 到底是什么
    • 1.5 为什么 Git 分支"几乎零成本"
  • 二、分支的创建与切换
    • 2.1 查看当前所有分支
    • 2.2 创建分支
    • 2.3 切换分支
    • 2.4 创建并切换(最常用)
    • 2.5 在指定 commit 上创建分支
    • 2.6 删除分支
    • 2.7 实战演练
  • 三、分支合并:fast-forward 模式
    • 3.1 什么是 fast-forward
    • 3.2 实际例子
    • 3.3 什么时候不会 fast-forward
  • 四、--no-ff 模式合并:保留分支历史
    • 4.1 为什么需要 --no-ff
    • 4.2 怎么用 --no-ff
    • 4.3 什么时候用 --no-ff
    • 4.4 查看分支图:git log --graph
  • 五、💥 合并冲突:原理与解决
    • 5.1 什么情况下会冲突
    • 5.2 看冲突文件
    • 5.3 解决冲突
    • 5.4 验证冲突解决完没
    • 5.5 取消合并
    • 5.6 用工具解决冲突
    • 5.7 实战示例:完整的冲突解决流程
  • 六、Bug 分支与 stash 暂存
    • 6.1 场景重现
    • 6.2 git stash 暂存
    • 6.3 stash 常用命令
    • 6.4 多个 stash 的管理
    • 6.5 暂存未追踪的文件
    • 6.6 stash 实战工作流
  • 七、分支管理策略:feature / release / hotfix
    • 7.1 三大经典分支
    • 7.2 feature(功能分支)
    • 7.3 release(预发布分支)
    • 7.4 hotfix(紧急修复分支)
    • 7.5 分支命名规范
  • 八、企业级开发模型:引子
    • 九、分支管理实操:完整工作流演示
      • 十、本节常见问题解答
        • 为什么有人的 Git 终端有颜色?
        • 什么是--no-ff模式合并?
        • git stash pop多个 stash 会怎样?
        • git stash和git stash push有什么区别?
        • 怎么判断合并冲突有没有解决完?
      • 十一、实战练习:分支管理"五连击"
        • 十二、关键命令速查表
          • 十三、几个思考题
            • fast-forward 合并和 --no-ff 合并的本质区别是什么?
            • stash 后忘了 stash 列表里有什么,怎么办?
            • 删除分支前,怎么确认这个分支的工作已经合并了?
            • 合并冲突解决到一半,想放弃怎么办?
            • 怎么删除远程已不存在的远程跟踪分支?

          前言

          如果让你给 Git 的功能排个"惊艳榜",分支管理一定稳坐第一。

          但不少新手一提"分支"就头大:HEAD 是什么?fast-forward 是啥?为什么合并会冲突?git stash 又是干啥的?

          别慌。本篇就是来"治"这个的。我们从分支的本质讲起,把分支的"前世今生"画成时间线,让你彻底看懂 HEAD、分支指针、合并提交到底是什么;然后手把手教你创建、切换、合并、删除分支;再深入到合并冲突的真实解决过程;最后讲 Bug 分支stash 暂存feature / release / hotfix 三大经典分支策略,以及企业级开发模型的引子(详细模型我们留到第 5 篇专题展开)。

          本节目标:让你彻底玩转 Git 分支管理。学完之后,你能像资深开发者一样用分支隔离功能开发、用 stash 保护未完成代码、用冲突解决流程搞定团队合并,并对企业级分支模型有清晰的整体认知。

          通过本文,你将掌握:

          技能 应用场景
          从时间线角度理解分支本质 看懂 Git 内部指针机制
          熟练创建/切换/合并/删除分支 日常开发必备
          掌握 fast-forward 与 --no-ff 模式合并 写出清晰的提交历史
          解决真实合并冲突 团队协作必踩的坑
          用 git stash 暂存未完成工作 紧急修复 Bug 不慌
          理解 feature / release / hotfix 三大分支策略 进阶团队协作

          前置知识: 熟练掌握第 1 篇的本地仓库操作(init、add、commit、log、reset、checkout)。本篇命令同样在 user@localhost 虚拟环境下演示。

          一、分支是什么:从时间线讲起

          要玩转分支,先得搞清楚分支到底是什么

          1.1 一个生活中的类比

          想象你正在写一本书,主线版本写到第 5 章。某天你想试试一个疯狂的想法——把第 3 章结尾反转到完全不同的方向。

          最笨的办法:把整本书复制一份,在副本上改。改得不好,主线还在;改得好,再合并回主线。

          Git 的"分支"就是这个副本机制——而且它是几乎零成本的。

          1.2 Git 的分支本质

          很多人以为 Git 分支是"复制整个项目目录"。错!

          Git 的分支只是一个指向某个 commit 的可移动指针

          Git 仓库的初始分支叫 master(现在很多项目改用 main),它指向你最新一次的提交。每提交一次,master 就往前移动一步。

          看图就懂:

          时间线(master 一直往前走)

                    C0 ── C1 ── C2 ── C3  ← master 指向最新
                                      ↑
                                    (HEAD)

          • 每一个 C0C1… 是一次提交
          • master 是一个指针,永远指向当前分支的最新提交
          • HEAD 是一个特殊指针,指向"你当前所在的分支"

          1.3 创建分支后,时间线长这样

          当你在 C2 处创建了一个叫 dev 的分支:

          时间线(master 和 dev 分叉)

                            master
                              ↓
                    C0 ── C1 ── C2 ── C3
                                      ↓
                                     dev

          实际工作流通常是这样的:

                            master
                              ↓
                    C0 ── C1 ── C2 ── C3 ── C5   ← master 继续往前走
                          \                ↑
                           \              (合并点)
                            C2'─ C4 ──────┘
                               ↑
                             dev

          • C2 处创建 dev 分支
          • dev 分支独立提交了 C4
          • master 分支独立提交了 C5
          • 最后把 dev 合并回 master

          1.4 HEAD 到底是什么

          HEAD 是一个指针文件,记录在 .git/HEAD 里。它指向当前所在的分支

          # 查看 HEAD 的指向
          cat .git/HEAD
          # 输出:ref: refs/heads/master

          这表示:当前所在分支是 master,HEAD 实际指向的是 master 这个指针。

          切换分支时,HEAD 的指向也会改变。比如 git checkout dev 后,.git/HEAD 就会变成 ref: refs/heads/dev。

          1.5 为什么 Git 分支"几乎零成本"

          别的版本控制系统(SVN、CVS)创建分支要把所有文件复制一份,耗时耗空间。

          Git 呢?只创建一个新指针

          # 在当前提交上创建一个叫 dev 的分支
          git branch dev
          
          # 实际就是创建了 .git/refs/heads/dev 文件
          # 文件内容:当前 commit 的 SHA-1
          cat .git/refs/heads/dev
          # 输出:abc1234567890abcdef1234567890abcdef123456
          

          创建完没有切换到 dev,要切换还需要 git checkout dev

          创建分支用 41 字节(commit id 的 SHA-1 长度)就够了。这就是为什么 Git 在 Linux 这种千万行代码项目里也能毫秒级创建分支。

          二、分支的创建与切换

          理论讲够了,开始动手。

          2.1 查看当前所有分支

          git branch
          # 输出:
          # * master
          # 带 * 号的是当前所在分支
          

          -a 看所有分支(包括远程分支):

          git branch -a
          

          2.2 创建分支

          # 创建一个叫 dev 的分支(基于当前所在分支)
          git branch dev
          
          # 验证
          git branch
          # 输出:
          #   dev
          # * master
          # (dev 已存在,但 HEAD 还在 master)
          

          2.3 切换分支

          git checkout 是切换分支的老牌命令(Git 2.23 之前唯一方式):

          git checkout dev
          
          # 验证
          git branch
          # 输出:
          # * dev
          #   master
          # (* 号跳到了 dev)
          

          注意:切换分支前要保证当前分支的工作区是干净的(没有未提交的改动),否则 Git 会拒绝切换,或者把改动"带"到新分支。

          2.4 创建并切换(最常用)

          99% 的场景下,你要的是"创建新分支 + 立即切过去"。一条命令搞定

          # 老语法
          git checkout -b dev
          
          # 新语法(Git 2.23+,更清晰)
          git switch -c dev
          

          输出:

          Switched to a new branch 'dev'
          

          git switch 是 Git 2.23 引入的新命令,专门做"切换"这件事(git checkout 身兼多职容易混淆)。switch 让命令语义更清晰。新项目建议用 switch。

          2.5 在指定 commit 上创建分支

          # 基于某个 commit id 创建分支
          git branch  
          
          # 基于远程分支创建本地分支
          git branch  origin/
          

          2.6 删除分支

          # 删除已合并的分支(-d 是 --delete 的简写)
          git branch -d dev
          
          # 强制删除(即使没合并也删,慎用!)
          git branch -D dev
          

          -D 大写是强制删除,可能丢失未合并的提交。永远不要在你不熟悉的分支上用 -D。

          2.7 实战演练

          # 1. 看现在在哪
          git branch
          # * master
          
          # 2. 创建并切到 dev
          git checkout -b dev
          # Switched to a new branch 'dev'
          
          # 3. 在 dev 上做改动
          echo "这是 dev 分支的修改" >> ReadMe
          git add ReadMe
          git commit -m "dev: 添加 dev 分支说明"
          
          # 4. 切回 master
          git checkout master
          # Switched to branch 'master'
          
          # 5. 看 ReadMe 的内容
          cat ReadMe
          # (dev 分支的修改不见了!因为它在 dev 分支上)
          
          # 6. 把 dev 合并回 master
          git merge dev
          # 输出(fast-forward 模式):
          # Updating abc1234..def5678
          # Fast-forward
          #  ReadMe | 1 +
          #  1 file changed, 1 insertion(+)
          
          # 7. dev 分支可以删了
          git branch -d dev
          

          到这里你已经玩过分支的"创建 → 切换 → 提交 → 合并 → 删除"全流程。下一节我们深入看合并模式。

          三、分支合并:fast-forward 模式

          合并分支用 git merge 命令。但合并方式分两种:fast-forward(快进)和 --no-ff(非快进)。

          3.1 什么是 fast-forward

          当 master 分支在 dev 创建后没有任何新的提交,dev 分支顺着 master 走,合并时直接"快进"指针到 dev 最新 commit。不会产生新的合并提交

          时间线:

          合并前:
                          master
                            ↓
          C0 ── C1 ── C2 ── C3
                      \
                       C2'─ C4
                           ↑
                          dev

          合并后(fast-forward):
                          master, dev
                              ↓
          C0 ── C1 ── C2 ── C3 ── C4

          实际命令:

          # 在 master 上执行
          git merge dev
          # 输出:
          # Updating abc1234..def5678
          # Fast-forward
          #  ReadMe | 1 +
          #  1 file changed, 1 insertion(+)
          

          注意 “Fast-forward” 这个词——它告诉我们这次是直接移动 master 指针到 C4,没有产生新 commit

          fast-forward 是 Git 合并的"最优解"——历史是一条直线,没有多余的合并节点,干净利落。

          3.2 实际例子

          # 准备工作
          mkdir -p /home/user/test/merge-test
          cd /home/user/test/merge-test
          git init
          echo "v1" > ReadMe
          git add .
          git commit -m "v1"
          
          # 创建 dev 分支
          git checkout -b dev
          echo "v2 in dev" >> ReadMe
          git add .
          git commit -m "v2 in dev"
          
          # 切回 master,合并
          git checkout master
          git merge dev
          # Fast-forward
          #  ReadMe | 1 +
          #  1 file changed, 1 insertion(+)
          
          # 查看日志
          git log --pretty=oneline
          # def5678 (HEAD -> master, dev) v2 in dev
          # cff9d1e v1
          # 注意:master 和 dev 都指向同一个 commit
          

          3.3 什么时候不会 fast-forward

          当 master 在 dev 之后又有新提交时,无法 fast-forward。看图:

          合并前:
                           C0 ── C1 ── C2 ── C3  ← master
                                      \
                                       C2'─ C4
                                            ↑
                                           dev

          这种结构没办法直接把 master 移到 C4(因为会丢掉 C3)。Git 会做三方合并,产生一个新的合并提交

          合并后(三方合并):
                           C0 ── C1 ── C2 ── C3 ── C5 (merge commit)  ← master
                                      \                /
                                       C2'─ C4 ───────
                                            ↑
                                           dev

          三方合并需要你写合并提交信息(Git 会弹出编辑器)。可以加 -m "xxx" 直接写。

          四、--no-ff 模式合并:保留分支历史

          虽然 fast-forward 看起来很完美,但它有个小缺点分不清哪些提交是哪个分支做的

          4.1 为什么需要 --no-ff

          看下面这个历史:

          Fast-forward 后的历史(看不出来分叉过):
          
          C0 ── C1 ── C2 ── C3 ── C4
          

          我完全看不出"哪些提交是在 dev 分支上做的"。功能分支被"抹平"了

          而用 --no-ff

          --no-ff 合并后的历史(能看出分叉):

          C0 ── C1 ── C2 ── C3 ── C5 (merge commit)
                      \                /
                       C2'─ C4 ───────

          C4 是在 dev 分支上做的,C5 是合并提交——一目了然。

          4.2 怎么用 --no-ff

          # 强制使用非 fast-forward 合并
          git merge --no-ff -m "合并 dev 分支" dev
          

          输出:

          Merge made by the 'recursive' strategy.
           ReadMe | 1 +
           1 file changed, 1 insertion(+)

          注意:这次是 “Merge made by the ‘recursive’ strategy”,不是 Fast-forward产生了新的 merge commit

          4.3 什么时候用 --no-ff

          场景 推荐模式
          个人小项目 / 临时分支 fast-forward(默认)
          团队协作的功能分支 –no-ff(强烈推荐)
          上线分支 / 长期维护分支 –no-ff
          简单的本地实验 fast-forward

          企业开发中,功能分支合并几乎都用 --no-ff。这样历史里能清晰看到"哪些功能是哪个分支做的",对后期维护和代码审查帮助极大。

          4.4 查看分支图:git log --graph

          看分支历史结构的最强工具:

          # 图形化显示
          git log --graph --pretty=oneline --abbrev-commit
          
          # 加上 --all 看所有分支
          git log --graph --pretty=oneline --abbrev-commit --all
          

          输出类似:

          *   c123456 (HEAD -> master) Merge branch 'dev'
          |\
          | * d789abc (dev) v2 in dev
          |/
          * a456789 v1
          

          这个图清晰显示:master 和 dev 在 v1 后分叉,dev 提交了 v2,master 又合并了 dev。

          建议把这条命令设个别名:

          git config --global alias.lg "log --graph --pretty=oneline --abbrev-commit --all"
          

          以后直接 git lg 就能看漂亮的分支图。

          五、💥 合并冲突:原理与解决

          合并最让人头疼的就是冲突(Conflict)。但理解了原理,解决起来其实很简单。

          5.1 什么情况下会冲突

          当两个分支修改了同一个文件的同一行,Git 没办法自动判断保留谁的内容,就会触发冲突。

          举个例子:

          # 1. 在 master 上改 ReadMe
          git checkout master
          echo "hello master" > ReadMe
          git add .
          git commit -m "master: 改 ReadMe"
          
          # 2. 切到 dev 改同一行
          git checkout dev
          echo "hello dev" > ReadMe
          git add .
          git commit -m "dev: 改 ReadMe"
          
          # 3. 切回 master 合并 dev
          git checkout master
          git merge dev
          # 输出:
          # Auto-merging ReadMe
          # CONFLICT (content): Merge conflict in ReadMe
          # Automatic merge failed; fix conflicts and then commit the result.
          

          出现 CONFLICT 就是冲突了

          5.2 看冲突文件

          打开冲突文件(这里是 ReadMe),你会看到这样的"奇怪"内容:

          <<<<<<>>>>>> dev
          

          这段标记的含义:

          • <<<<<<< HEAD:当前分支(master)的内容
          • =======:分隔符
          • >>>>>>> dev:要合并过来的分支(dev)的内容

          5.3 解决冲突

          三步走:

          ① 手动编辑文件

          保留你想要的内容(或者两个都保留,或合并成新的内容):

          # 编辑后:
          hello master and dev
          

          ② 标记解决冲突

          git add ReadMe
          

          ③ 完成合并

          git commit -m "解决 ReadMe 合并冲突"
          

          git add 不是"添加文件",在合并场景下它的意思是"我已解决冲突,标记这个文件为已解决"。

          5.4 验证冲突解决完没

          git status 会告诉你还有没有未解决的冲突:

          git status
          # 输出(未解决):
          # Unmerged paths:
          #   (use "git add ..." to mark resolution)
          #         both modified:   ReadMe
          # 
          # 输出(已解决):
          # Changes to be committed:
          #         modified:   ReadMe
          

          看到 “Unmerged paths” 就是没解决完。

          5.5 取消合并

          如果冲突搞砸了想放弃合并:

          git merge --abort
          

          这条命令会回退到合并前的状态,相当于"撤销合并"。

          5.6 用工具解决冲突

          手动改文件太累?很多 IDE/编辑器有冲突解决工具:

          • VS Code:内置冲突解决器,左边选 ours / theirs,右边实时预览
          • IntelliJ IDEA:三栏布局(base / ours / theirs)
          • Beyond Compare:专业的 diff 工具
          • Meld:免费跨平台 diff 工具

          团队规模大了,强烈建议团队成员用同一种冲突解决工具,避免风格不一致。

          5.7 实战示例:完整的冲突解决流程

          # 假设冲突发生
          git merge dev
          # CONFLICT 提示
          
          # 1. 看哪些文件冲突
          git status
          # Unmerged paths: ReadMe
          
          # 2. 编辑 ReadMe(保留两个版本)
          vim ReadMe
          # 改成你想要的内容,删除 <<<<<<>>>>>> 标记
          
          # 3. 标记解决
          git add ReadMe
          
          # 4. 查状态(应该没有 Unmerged paths 了)
          git status
          # Changes to be committed: ReadMe
          
          # 5. 完成合并
          git commit -m "merge dev: 解决 ReadMe 冲突"
          
          # 6. 验证
          git log --graph --pretty=oneline --abbrev-commit
          # *   c123456 (HEAD -> master) merge dev: 解决 ReadMe 冲突
          # |\
          # | * d789abc (dev) dev: 改 ReadMe
          # |/
          # * a456789 master: 改 ReadMe
          

          完美!冲突解决后,分支历史清晰可读。

          六、Bug 分支与 stash 暂存

          实际开发中,正在写一个功能写到一半,突然发现线上有 Bug 要立刻修——这种场景太常见了。怎么办?

          6.1 场景重现

          # 1. 你正在 dev 分支开发一个"用户登录"功能,写到一半
          git checkout -b dev
          echo "登录功能代码" > login.py
          git add login.py
          git commit -m "feat: 登录功能 - 1"
          
          echo "登录功能代码 - 2" >> login.py
          # (注意:这里没 commit,因为还没写完!)
          

          现在老板突然说:线上付款功能有 Bug,立刻修!

          不能

          • 直接 git checkout master 切分支(会带着未提交的文件)
          • git commit 把没写完的代码提交了(污染历史)

          正确做法:用 git stash 暂存起来

          6.2 git stash 暂存

          # 把当前工作区和暂存区的改动"打包"起来
          git stash
          
          # 输出:
          # Saved working directory and index state WIP on dev: abc1234 feat: 登录功能 - 1
          

          stash 本质是把改动保存到一个栈结构里,工作区瞬间变成"上次 commit 的干净状态"。

          现在你可以放心切换分支修 Bug 了:

          # 2. 切到主分支修 Bug
          git checkout master
          
          # 3. 创建 bugfix 分支
          git checkout -b bugfix-001
          
          # 4. 修复 Bug 并提交
          echo "付款 Bug 修复" > pay.py
          git add pay.py
          git commit -m "fix: 修复付款 Bug"
          
          # 5. 切回 master 合并 bugfix
          git checkout master
          git merge --no-ff -m "merge bugfix-001" bugfix-001
          
          # 6. 删除 bugfix 分支
          git branch -d bugfix-001
          

          修完 Bug,回到 dev 分支继续写你的登录功能

          # 7. 切回 dev 分支
          git checkout dev
          
          # 8. 把暂存的改动"恢复"出来
          git stash pop
          

          git stash pop 会把最新的 stash 恢复到工作区,并从 stash 栈里删除

          6.3 stash 常用命令

          # 暂存当前改动(不带消息)
          git stash
          
          # 暂存并加消息(推荐,方便查找)
          git stash push -m "修复登录功能写到一半"
          
          # 查看所有 stash
          git stash list
          
          # 恢复最新 stash(不删除 stash)
          git stash apply
          
          # 恢复最新 stash(删除 stash,等价于 apply + drop)
          git stash pop
          
          # 恢复指定 stash
          git stash apply stash@{0}    # 恢复第 1 个
          git stash apply stash@{1}    # 恢复第 2 个
          
          # 删除指定 stash
          git stash drop stash@{0}
          
          # 清空所有 stash
          git stash clear
          

          6.4 多个 stash 的管理

          git stash push -m "改了一半的登录功能"
          git stash push -m "性能优化草稿"
          git stash push -m "UI 重构中"
          
          git stash list
          # stash@{0}: On dev: UI 重构中
          # stash@{1}: On dev: 性能优化草稿
          # stash@{2}: On dev: 改了一半的登录功能
          

          stash 是个栈(LIFO:后进先出):

          git stash pop   # 恢复 stash@{0}(UI 重构中)
          git stash pop   # 恢复 stash@{1}(性能优化草稿)
          git stash pop   # 恢复 stash@{2}(改了一半的登录功能)
          

          6.5 暂存未追踪的文件

          默认 git stash 不暂存未追踪的文件(新创建但没 add 的):

          echo "新文件" > new.txt  # 创建新文件,没 add
          git stash
          # 暂存的是已追踪文件的改动,new.txt 不会暂存
          

          想暂存未追踪文件,加 -u

          git stash -u
          # 或
          git stash push -u -m "包含新文件"
          

          6.6 stash 实战工作流

          # 1. 当前在 dev 分支,工作区有未提交的改动
          git status
          # modified: login.py
          
          # 2. 老板紧急派活,先把当前改动暂存
          git stash push -m "登录功能 - 未完成"
          
          # 3. 切到 hotfix 分支修紧急 Bug
          git checkout master
          git checkout -b hotfix
          # ... 修 Bug、提交、合并、删除分支 ...
          
          # 4. 回到 dev 分支
          git checkout dev
          
          # 5. 恢复之前的改动
          git stash pop
          

          这是企业里每天都在发生的工作流。git stash 就是你的"工作区保险箱"。

          七、分支管理策略:feature / release / hotfix

          前面我们学的是"操作",现在讲"策略"——一个团队应该怎么用分支

          7.1 三大经典分支

          分支类型 作用 来源 归宿 生命周期
          feature 开发新功能 develop develop 功能完成即删
          release 发布前的稳定分支 develop master + develop 发布完即删
          hotfix 紧急修复线上 Bug master master + develop 修完即删

          7.2 feature(功能分支)

          场景:开发一个新功能。

          # 从 develop 创建 feature 分支
          git checkout develop
          git checkout -b feature/user-login
          
          # 开发...
          git add .
          git commit -m "feat: 用户登录"
          
          # 完成后合并回 develop
          git checkout develop
          git merge --no-ff -m "merge feature/user-login" feature/user-login
          
          # 删除 feature 分支
          git branch -d feature/user-login
          

          feature 分支通常一个人用(避免冲突),完成后合并回 develop。

          7.3 release(预发布分支)

          场景:要发版了,做最后的测试和 Bug 修复。

          # 从 develop 创建 release 分支
          git checkout develop
          git checkout -b release/v1.0.0
          
          # 测试 + 修小 Bug
          git commit -m "fix: 修复测试发现的 Bug"
          
          # 测试通过,发布到 master
          git checkout master
          git merge --no-ff -m "release v1.0.0" release/v1.0.0
          git tag v1.0.0  # 打 tag 标记版本
          
          # 同步回 develop
          git checkout develop
          git merge --no-ff -m "merge release/v1.0.0 back to develop" release/v1.0.0
          
          # 删除 release 分支
          git branch -d release/v1.0.0
          

          为什么要同步回 develop?因为 release 分支可能修了 Bug,develop 也要拿到这些修复。

          7.4 hotfix(紧急修复分支)

          场景:线上版本出问题了,要立刻修。

          # 从 master 创建 hotfix 分支
          git checkout master
          git checkout -b hotfix/pay-bug
          
          # 修复 Bug
          git add .
          git commit -m "fix: 紧急修复付款 Bug"
          
          # 修复完成,合并到 master
          git checkout master
          git merge --no-ff -m "hotfix pay-bug" hotfix/pay-bug
          git tag v1.0.1  # 升级版本号
          
          # 同步到 develop
          git checkout develop
          git merge --no-ff -m "merge hotfix/pay-bug" hotfix/pay-bug
          
          # 删除 hotfix 分支
          git branch -d hotfix/pay-bug
          

          hotfix 只修紧急的、能快速解决的 Bug。复杂问题应该走 feature 分支完整修复。

          7.5 分支命名规范

          好命名 = 好维护:

          类型 命名示例
          功能分支 feature/user-loginfeature/shopping-cart
          预发布分支 release/v1.0.0release/2024-q3
          紧急修复 hotfix/pay-bughotfix/crash-2024-09
          个人开发 dev//xxx

          八、企业级开发模型:引子

          你以为 feature / release / hotfix 就是全部了?不,这是经典 Git Flow 模型的核心

          一个完整的企业级开发模型远不止这三个分支。它涉及:

          • 长期分支 vs 短期分支的搭配
          • 环境对应(开发 / 测试 / 预发布 / 正式)
          • 角色分工(开发 / 测试 / 运维 / 技术经理)
          • 发版节奏(每周 / 每月 / 紧急)
          • 回滚机制(出问题了怎么秒级回滚)

          本节限于篇幅只讲 feature / release / hotfix 三大基础策略的单独使用完整的企业级开发模型(Git Flow / GitHub Flow / GitLab Flow)将在第 5 篇《企业级 Git 开发模型:从小作坊到工业级规范》 里专题展开。

          到那里我们会看到:

          • 一个 10 人团队怎么用 5 种分支协作
          • 不同公司为什么选不同的模型
          • 大厂的真实发版流程长什么样
          • 怎么把 Git 用成"生产线"而不是"备份工具"

          九、分支管理实操:完整工作流演示

          把这一篇的所有知识点串起来,做一个完整的"个人开发工作流"演示。

          任务:在 master 上开发"登录功能",用 dev 隔离,用 stash 应对紧急情况。

          # 1. 准备工作
          mkdir -p /home/user/test/branch-workflow
          cd /home/user/test/branch-workflow
          git init
          echo "v1" > app.py
          git add .
          git commit -m "init: 项目初始化"
          
          # 2. 创建并切到 dev 分支
          git checkout -b dev
          
          # 3. 在 dev 上开发登录功能
          echo "def login(): pass" > login.py
          git add login.py
          git commit -m "feat(login): 添加登录函数"
          
          # 4. 突然老板让修付款 Bug
          # 把当前未提交的改动暂存(假设我们正在改 login.py)
          echo "def login_v2(): pass" >> login.py
          git stash push -m "login v2 写到一半"
          
          # 5. 切到 master 修付款 Bug
          git checkout master
          git checkout -b hotfix/pay-bug
          echo "def pay(): fix" > pay.py
          git add pay.py
          git commit -m "hotfix(pay): 修复付款 Bug"
          
          # 6. 合并回 master 并打 tag
          git checkout master
          git merge --no-ff -m "merge hotfix/pay-bug" hotfix/pay-bug
          git tag v1.0.1
          git branch -d hotfix/pay-bug
          
          # 7. 回到 dev 继续开发
          git checkout dev
          git stash pop   # 恢复 login v2 的改动
          
          # 8. 完成登录功能
          git add login.py
          git commit -m "feat(login): 完善登录功能"
          
          # 9. 合并到 master
          git checkout master
          git merge --no-ff -m "merge dev" dev
          git tag v1.1.0
          
          # 10. 删除 dev 分支
          git branch -d dev
          
          # 11. 看完整历史
          git log --graph --pretty=oneline --abbrev-commit --all
          # *   d789abc (HEAD -> master, tag: v1.1.0) merge dev
          # |\
          # | * c456def (tag: v1.0.1) hotfix(pay): 修复付款 Bug
          # |/
          # * b123456 init: 项目初始化
          

          跑一遍这个流程,你对分支的"创建 → 切换 → 暂存 → 合并 → 删除 → 标签"就有完整感觉了。

          十、本节常见问题解答

          挑了 5 个跟分支管理最相关的问题,逐一解答。

          为什么有人的 Git 终端有颜色?

          答:配置颜色显示。

          Git 默认在某些终端会显示颜色帮助区分。要开启/关闭:

          # 开启颜色(推荐)
          git config --global color.ui auto
          
          # 关闭颜色
          git config --global color.ui false
          

          auto 模式:输出到终端时显示颜色,输出到文件或管道时不显示,最智能。

          颜色不是"花里胡哨",是减少误操作的关键。比如红色的 deleted 比黑白文字警告更醒目。

          什么是--no-ff模式合并?

          答:保留分支历史的合并方式。

          git merge --no-ff 即使能 fast-forward,也强制创建合并提交,让历史能看出"哪些提交是哪个分支做的"。

          # 不管能不能 fast-forward,都产生 merge commit
          git merge --no-ff -m "merge feature/login" feature/login
          

          团队开发的功能分支强烈建议用 --no-ff。这样 PR 评审、回溯功能、查 Bug 都很方便。

          git stash pop多个 stash 会怎样?

          答:按 LIFO(后进先出)顺序恢复。

          git stash 把当前工作区"打包"暂存起来,git stash pop 把最新的 stash 恢复出来。多个 stash 会按栈结构组织:

          git stash       # 暂存当前
          git stash       # 暂存第二个
          git stash list  # 查看所有 stash
          git stash pop   # 恢复最新(即第二个)
          git stash pop   # 恢复最早(即第一个)
          

          stash 不是长期存储方案。stash 默认可能 30 天后被清理。重要的代码一定要 commit 提交,不能依赖 stash。

          git stash和git stash push有什么区别?

          答:几乎没有区别。

          git stashgit stash push 的简写(Git 2.13+ 引入)。git stash push 更明确,支持更多参数:

          # 等价
          git stash
          git stash push
          
          # 推 stash 时附加信息
          git stash push -m "修复登录bug"
          

          推荐用 git stash push -m "说明",给自己和别人留个上下文。

          怎么判断合并冲突有没有解决完?

          答:用 git status 看是否有 unmerged 标记。

          冲突时 git status 会显示:

          Unmerged paths:
            (use "git add ..." to mark resolution)
                  both modified:   file.txt
          

          解决完冲突后 git add 标记解决,再 git status 就看不到 Unmerged paths 了。

          解决冲突后一定要仔细看 diff!两个分支的修改可能都"看起来对",但合并后逻辑可能错。提交前用 IDE 走读一遍。

          十一、实战练习:分支管理"五连击"

          来练 5 个连续动作,体验真实开发场景。

          任务:

          1. 创建一个叫 git-branch-practice 的仓库,提交一个 app.py(内容任意)
          2. 创建 feature/pay 分支,加一个 pay.py 函数并提交
          3. 切回 master,创建 feature/login 分支
          4. feature/loginapp.py(加一行 import),切回 master 也改 app.py(加一行注释)
          5. feature/login 合并到 master,解决冲突,合并 feature/pay 验证 fast-forward
          6. 删除所有临时分支,用 git log --graph 看历史

          参考答案:

          # 1. 初始化
          mkdir -p /home/user/test/git-branch-practice
          cd /home/user/test/git-branch-practice
          git init
          echo "print('hello')" > app.py
          git add .
          git commit -m "init: app.py"
          
          # 2. feature/pay
          git checkout -b feature/pay
          echo "def pay(): pass" > pay.py
          git add pay.py
          git commit -m "feat(pay): 添加支付函数"
          
          # 3. feature/login
          git checkout master
          git checkout -b feature/login
          echo "import os" >> app.py
          git add app.py
          git commit -m "feat(login): 添加 os 导入"
          
          # 4. 回到 master 也改 app.py
          git checkout master
          echo "# 入口文件" >> app.py
          git add app.py
          git commit -m "docs: 添加 app.py 注释"
          
          # 5. 合并 feature/login(会有冲突)
          git merge feature/login
          # CONFLICT 提示
          
          # 编辑 app.py 解决冲突(保留两边的修改):
          # print('hello')
          # # 入口文件
          # import os
          git add app.py
          git commit -m "merge feature/login: 解决冲突"
          
          # 6. 合并 feature/pay(fast-forward)
          git merge feature/pay
          # Fast-forward
          #  pay.py | 1 +
          #  1 file changed, 1 insertion(+)
          
          # 7. 删除分支
          git branch -d feature/login
          git branch -d feature/pay
          
          # 8. 看历史
          git log --graph --pretty=oneline --abbrev-commit --all
          

          跑完这五步,你对分支管理就有"肌肉记忆"了。

          十二、关键命令速查表

          命令 作用
          git branch 查看本地分支
          git branch -a 查看所有分支(含远程)
          git branch 创建分支
          git branch -d 删除已合并的分支
          git branch -D 强制删除分支
          git checkout 切换分支(老语法)
          git checkout -b 创建并切换分支
          git switch 切换分支(新语法)
          git switch -c 创建并切换分支
          git merge 合并指定分支到当前分支
          git merge --no-ff 非 fast-forward 合并
          git merge --abort 取消合并
          git stash 暂存当前改动
          git stash push -m "..." 暂存并加消息
          git stash list 查看所有 stash
          git stash pop 恢复并删除最新 stash
          git stash apply 恢复但不删除
          git stash drop 删除指定 stash
          git tag 打 tag
          git log --graph --all 图形化看分支历史

          十三、几个思考题

          学完本文,来试试回答这些问题:

          fast-forward 合并和 --no-ff 合并的本质区别是什么?

          答:是否产生新的 merge commit。

          • fast-forward:当被合并的分支是当前分支的直接祖先时,Git 直接把当前分支指针移动到被合并分支的最新 commit,不产生新 commit
          • –no-ff:强制产生一个新的 merge commit,把两条分支的历史连接起来。

          选择建议:功能分支合并用 --no-ff(保留分支历史),简单同步用 fast-forward(保持历史干净)。

          git log --graph 时,fast-forward 是一条直线,–no-ff 是一个"分叉再合并"的 Y 字形。

          stash 后忘了 stash 列表里有什么,怎么办?

          答:用 git stash list + git stash show

          # 1. 看所有 stash
          git stash list
          # stash@{0}: On dev: 改了一半的登录功能
          # stash@{1}: On dev: 性能优化草稿
          
          # 2. 看某个 stash 的内容(默认只看文件改动概览)
          git stash show stash@{0}
          
          # 3. 看完整 diff
          git stash show -p stash@{0}
          

          如果 stash 内容太多忘了是什么,用 git stash show -p 看 diff。看到不认识的代码,别乱 pop,先开新分支验证。

          stash 不是 commit,没有 message 也能存。养成 git stash push -m "说明" 的习惯,一个月后看也认得。

          删除分支前,怎么确认这个分支的工作已经合并了?

          答:先看分支列表,再看 merged 列表。

          # 1. 看所有分支
          git branch -a
          
          # 2. 看哪些分支已合并到当前分支
          git branch --merged
          
          # 3. 看哪些分支**未**合并
          git branch --no-merged
          

          --no-merged 列出的分支千万别 -d,要用 -D 强制删(且必须确认分支上的工作不要了)。

          长期不清理的"僵尸分支"会让 git branch 列表很乱。定期(比如每两周)review 一次 merged / no-merged 列表。

          合并冲突解决到一半,想放弃怎么办?

          答:git merge --abort(合并中)或 git rebase --abort(rebase 中)。

          # 合并冲突中放弃合并
          git merge --abort
          
          # rebase 冲突中放弃
          git rebase --abort
          

          执行后,工作区会恢复到合并/rebase 之前的状态,相当于"撤销这次操作"。

           比 --abort 更狠的是 git reset --hard HEAD,但那会丢失所有未提交的改动--abort 是更安全的选择。

          怎么删除远程已不存在的远程跟踪分支?

          答:git remote prune origin

          # 删除远程已删除但本地还残留的远程跟踪分支
          git remote prune origin
          
          # 或者用 fetch 时自动清理
          git fetch --prune origin
          # 简写
          git fetch -p
          

          这条命令会同步远程状态,把本地那些"远程已经删了但本地还留着"的远程跟踪分支清理掉。

          远程分支积累多了 git branch -a 会很难看。每个工作日开始前 fetch -p 一下是好习惯。

          以上就是Git分支管理之分支创建、切换和合并操作详解的详细内容,更多关于Git分支操作的资料请关注北冥有鱼【www.ufcn.cn】其它相关文章!

          您可能感兴趣的文章:

          • Git实现将一个分支的特定提交合并到另一个分支
          • idea切换Git分支时保存未提交的文件方式
          • Git单分支与多分支的协作流程
          • Gitlab实现合并分支代码到主分支上
          • Git分支管理的核心命令科普指南
          • GIT合并分支的三种实现方式
          • Git分支参数 -u 和 -m 的具体使用
          • Git实现删除远程分支+本地分支
          本文地址:https://www.ufcn.cn/article/2425990.html

          如非特殊说明,本站内容均来自于网友自主分享,概不代表本站观点,如有任何问题我们都将在收到反馈后的第一时间进行处理!