Git从0到实战(三):分支管理 —— 团队协作的基石

5 阅读13分钟

没有分支的世界,混乱如麻

假设你在一个5人团队中开发一个电商项目。你们所有人都在 main 分支(之前叫 master)上直接改代码。这会发生什么?

  • 张三正在开发"用户评价"功能,代码写了一半,突然被要求修复一个线上 bug
  • 他没法把写了一半的代码提交(功能还没做完),也没法丢弃
  • 他只能硬着头皮在混乱的代码上修 bug,结果把半成品功能也一起提交上去了
  • 线上出现了一堆奇怪的报错,原因是张三的半成品代码被一起部署了

这就是没有分支的噩梦。分支就是来解决这个问题的——它让你可以在同一个项目中同时做多件事,互不干扰。


1. 分支是什么?一个生活化的理解

分支,就像你在玩一个角色扮演游戏:

graph LR
    Main[主线剧情<br/>main分支] --> B1[你选择了拯救公主<br/>save-princess分支]
    Main --> B2[你选择了拯救世界<br/>save-world分支]
    B1 --> M1[两条线汇合<br/>merge回主线]
    B2 --> M1
    M1 --> Next[主线继续推进]
  • 主线剧情 = main 分支,是项目的稳定版本
  • 拯救公主 = 一个功能分支,你在上面开发新功能
  • 拯救世界 = 另一个功能分支,你的同事在上面开发另一个功能
  • 汇合 = 功能开发完了,合并回 main 分支

每个分支都是一个独立的开发线,上面的修改不会影响其他分支。当你在"拯救公主"的剧情里死了无数次,也丝毫不会影响"拯救世界"的剧情线。

技术上的本质

从技术角度看,分支就是一个指向某个 commit 的指针

gitGraph
    commit id: &#34;A&#34;
    commit id: &#34;B&#34;
    branch feature
    checkout feature
    commit id: &#34;C&#34;
    commit id: &#34;D&#34;
    checkout main
    commit id: &#34;E&#34;
    commit id: &#34;F&#34;

在上图中:

  • main 分支指向 commit F
  • feature 分支指向 commit D
  • commit A 和 B 是两个分支的共同祖先

Git 的分支非常轻量——创建一个分支只是创建了一个指针,几乎是瞬间完成的。这也是 Git 相比 SVN 的一大优势(SVN 的分支是完整拷贝,很慢)。


2. git branch —— 查看和管理分支

查看分支

# 查看本地所有分支
git branch

# 查看所有分支(包括远程分支)
git branch -a

# 查看远程分支
git branch -r

# 查看每个分支的最后一次提交
git branch -v

# 查看已合并到当前分支的分支
git branch --merged

# 查看尚未合并到当前分支的分支
git branch --no-merged

输出示例:

* main
  feature/login
  feature/payment
  fix/header-bug
  • * 号标记的是当前所在分支
  • 绿色的是本地分支
  • 红色的是远程分支(git branch -a 时会显示,如 remotes/origin/main

创建分支

# 创建分支(但不会自动切换过去)
git branch feature/new-feature

# 创建分支并立刻切换到新分支(最常用)
git checkout -b feature/new-feature

# 或者用新的 switch 命令(Git 2.23+)
git switch -c feature/new-feature

删除分支

# 删除本地分支(已合并的)
git branch -d feature/old-feature

# 强制删除本地分支(即使没合并)
git branch -D feature/old-feature

# 删除远程分支
git push origin --delete feature/old-feature
# 或者简写
git push origin :feature/old-feature

重命名分支

# 重命名当前分支
git branch -m new-branch-name

# 重命名指定分支
git branch -m old-name new-name

3. git checkout 和 git switch —— 切换分支

git checkout(传统命令)

# 切换到已有分支
git checkout main

# 创建并切换到新分支
git checkout -b feature/new-feature

git checkout 是一个功能过载的命令——它既可以切换分支,又可以恢复文件(git checkout -- file),还可以创建分支。一个命令做太多事情,容易让人困惑。

为了解决这个问题,Git 2.23 版本引入了两个新命令:

  • git switch:专门用来切换分支
  • git restore:专门用来恢复文件

git switch(推荐使用,更清晰)

# 切换到已有分支
git switch main

# 创建并切换到新分支
git switch -c feature/new-feature

# 切换到上一个分支(超实用!)
git switch -

git switch - 是一个极其方便的命令。比如你在 feature/login 分支开发,临时需要切到 main 看个东西,然后马上切回来:

# 当前在 feature/login
git switch main    # 切到 main
# 看完东西了
git switch -       # 一键切回 feature/login

切换分支时工作区的影响

切换分支时,Git 会把你工作区的文件变成目标分支的状态。这有一个前提:你的工作区必须是干净的(没有未提交的修改)。

如果有未提交的修改,Git 会拒绝切换:

error: Your local changes to the following files would be overwritten by checkout:
        src/app.js
Please commit your changes or stash them before you switch branches.

解决方案有三种:

  1. 提交git add . && git commit -m "xxx"
  2. 丢弃git restore .(谨慎!)
  3. 暂存git stash(见下一节)

4. git stash —— 暂存你的工作

git stash 是 Git 中最实用的"救急"命令之一。它的作用是:把你当前工作区中所有未提交的修改"藏"起来,让工作区变干净。

使用场景

你正在开发一个新功能,代码写了一半,还没到能提交的地步。这时组长突然说:"线上有个紧急 bug,你赶快修一下。"

你怎么办?

  1. 把写了一半的代码提交?不行,功能还没做完,提交上去不完整
  2. 把代码丢弃?不行,写了半天白写了
  3. git stash
graph LR
    A[正在开发新功能<br/>代码未完成] -->|git stash| B[工作区变干净<br/>可以切分支修bug]
    B -->|修完bug切回来| C[git stash pop<br/>恢复之前的工作]
    C --> D[继续开发新功能]

基本用法

# 暂存当前所有修改
git stash

# 暂存时添加描述信息(推荐,方便后面查找)
git stash save "正在开发登录功能,保存进度"

# 查看所有暂存列表
git stash list

# 恢复最近一次暂存的修改(同时删除 stash 记录)
git stash pop

# 恢复最近一次暂存的修改(保留 stash 记录)
git stash apply

# 恢复指定的暂存
git stash pop stash@{1}
git stash apply stash@{1}

# 删除最近一次暂存
git stash drop

# 删除所有暂存
git stash clear

# 查看某次暂存的具体内容
git stash show -p stash@{0}

stash 的更多用法

# 暂存所有修改(包括未跟踪的新文件)
git stash -u
# 或
git stash --include-untracked

# 暂存所有修改(包括未跟踪和被忽略的文件)
git stash -a
# 或
git stash --all

# 暂存时保留暂存区(即 git add 过的文件保持不变)
git stash --keep-index

# 从 stash 中创建一个新分支
git stash branch new-branch-name stash@{0}

git stash branch 是一个特别实用的命令:当你恢复 stash 时遇到冲突,可以用这个命令创建一个新分支来解决冲突。

stash 列表解读

stash@{0}: WIP on feature/login: abc1234 添加登录表单验证
stash@{1}: WIP on main: def5678 修复首页样式
  • stash@{0}:索引,0 是最新的
  • WIP:Work In Progress,进行中的工作
  • on feature/login:当时所在的分支
  • abc1234:当时所在 commit 的哈希值

5. git merge —— 合并分支

当你在功能分支上开发完毕,就要把代码合并回 main 分支。这就是 git merge

基本用法

# 1. 先切换到目标分支(你要把代码合并到哪里)
git switch main

# 2. 合并源分支(把谁的代码合并进来)
git merge feature/login

这个操作的意思是:feature/login 分支的修改合并到当前所在的 main 分支。

两种合并方式:Fast-Forward 和 三方合并

Fast-Forward(快进合并)

当目标分支没有新提交时,Git 会使用 Fast-Forward 模式:

gitGraph
    commit id: &#34;A&#34;
    commit id: &#34;B&#34;
    branch feature
    checkout feature
    commit id: &#34;C&#34;
    commit id: &#34;D&#34;

合并前:main 在 B,feature 在 D。main 上没有 feature 不知道的新提交。

gitGraph
    commit id: &#34;A&#34;
    commit id: &#34;B&#34;
    commit id: &#34;C&#34;
    commit id: &#34;D&#34;

合并后:main 指针直接"快进"到 D。没有产生新的合并提交,历史是一条直线。

Fast-Forward 合并的条件:

  • 目标分支(main)在源分支(feature)创建后没有新提交
  • 两个分支的历史是线性的

三方合并(3-Way Merge)

当目标分支和源分支都有新提交时,Git 需要进行三方合并:

gitGraph
    commit id: &#34;A&#34;
    commit id: &#34;B&#34;
    branch feature
    checkout main
    commit id: &#34;E&#34;
    checkout feature
    commit id: &#34;C&#34;
    commit id: &#34;D&#34;

合并前:main 有 E,feature 有 C 和 D。两个分支都从 B 分叉了。

gitGraph
    commit id: &#34;A&#34;
    commit id: &#34;B&#34;
    commit id: &#34;E&#34;
    branch feature
    commit id: &#34;C&#34;
    commit id: &#34;D&#34;
    checkout main
    merge feature
    commit id: &#34;M&#34;

合并后:Git 创建了一个新的"合并提交"M,它有两个父提交——E 和 D。Git 会自动比较 A(共同祖先)、E(main 的版本)、D(feature 的版本)三者的差异,进行三方合并。

合并参数

# 禁用 Fast-Forward,强制创建合并提交
git merge --no-ff feature/login

# 仅当可以 Fast-Forward 时才合并(如果不能则拒绝)
git merge --ff-only feature/login

# 合并时添加自定义的合并提交信息
git merge -m "合并登录功能" feature/login

# 合并但不自动提交(让你检查后再手动提交)
git merge --no-commit feature/login

# 放弃合并(合并过程中遇到冲突想取消时使用)
git merge --abort

Fast-Forward vs --no-ff:该选哪个?

Fast-Forward--no-ff
历史记录一条直线,看不出分支的存在保留分支痕迹,清楚看到哪个功能何时合并
合并提交不产生产生一个 merge commit
回退方便性较难精确回退整个功能可以一键 revert 整个功能的合并
适用场景个人项目团队协作项目

建议:团队协作项目中,推荐使用 --no-ff。虽然会多一个合并提交,但历史记录更清晰,出问题时更容易定位和回退。


6. 分支策略 —— 团队是怎么用分支的?

不同的团队有不同的分支策略。面试中面试官可能会问:"你们公司用的是什么分支策略?"你需要知道常见的几种。

Git Flow

最经典的分支策略,适合有固定发布周期的项目。

gitGraph
    commit id: &#34;v1.0&#34;
    branch develop
    checkout develop
    commit id: &#34;开发中&#34;
    branch feature/login
    checkout feature/login
    commit id: &#34;登录开发&#34;
    commit id: &#34;登录完成&#34;
    checkout develop
    merge feature/login
    branch feature/payment
    checkout feature/payment
    commit id: &#34;支付开发&#34;
    commit id: &#34;支付完成&#34;
    checkout develop
    merge feature/payment
    branch release/1.1
    checkout release/1.1
    commit id: &#34;版本准备&#34;
    checkout main
    merge release/1.1
    checkout develop
    merge release/1.1

两种长期分支:

  • main(或 master):生产环境代码,只接受从 release 和 hotfix 分支的合并
  • develop:开发主分支,功能分支从这里分出,也合并回这里

三种临时分支:

  • feature/*:功能分支,从 develop 分出,开发完合并回 develop
  • release/*:发布分支,从 develop 分出,准备发布时创建。在这个分支上只做 bug 修复和版本号修改
  • hotfix/*:紧急修复分支,从 main 分出,修复线上紧急 bug。修复后同时合并回 main 和 develop

Git Flow 的优缺点:

优点缺点
结构清晰,分工明确分支太多,流程复杂
适合大型项目不适合持续部署(CI/CD)
版本管理规范小型团队会觉得太重

GitHub Flow

更简洁的分支策略,适合持续部署的 Web 项目。

gitGraph
    commit id: &#34;初始版本&#34;
    branch feature/login
    checkout feature/login
    commit id: &#34;登录开发&#34;
    commit id: &#34;CR修改&#34;
    checkout main
    merge feature/login
    branch feature/payment
    checkout feature/payment
    commit id: &#34;支付开发&#34;
    checkout main
    merge feature/payment

只有一个长期分支:

  • main:始终保持可部署状态

规则:

  1. main 分支上的任何东西都可以部署
  2. 开发新功能时,从 main 创建描述性的分支(如 feature/login
  3. 在本地分支上开发,定期 push 到远程
  4. 需要帮助或代码审查时,开 Pull Request
  5. PR 审核通过后,合并到 main
  6. 合并后立即部署

GitHub Flow 的优缺点:

优点缺点
简单,新手友好对版本管理不太友好
适合持续部署多人同时合并容易冲突
PR 驱动开发缺少发布缓冲

GitLab Flow

结合了 Git Flow 和 GitHub Flow 的优点,增加了环境分支(如 stagingproduction)。

国内互联网公司常见的做法

很多国内公司不会严格遵守某一种分支策略,而是采用简化版本:

  • main:线上代码
  • developdev:开发主分支
  • feature/xxx:功能分支
  • 直接从 feature/* 提 PR 到 develop
  • 发布时从 develop 合并到 main

7. 分支命名规范

好的命名规范让团队协作更顺畅:

前缀用途示例
feature/新功能开发feature/user-loginfeature/暗黑模式
fix/bugfix/Bug 修复fix/login-errorbugfix/首页白屏
hotfix/紧急线上修复hotfix/payment-crash
release/发布准备release/v2.0.0
refactor/代码重构refactor/api-layer
docs/文档更新docs/api-guide
chore/杂项(依赖更新等)chore/update-deps

命名建议:

  • 使用小写字母和连字符(-
  • 简短但有描述性
  • 可以包含日期或 issue 编号:feature/LOGIN-2026

8. 动手实战:分支操作全流程

让我们用一个完整的例子,把上面学到的所有命令串起来。

场景模拟

你接到任务:给电商项目添加"商品搜索"功能。同时,你还有上篇文章中的"按钮样式修复"需要继续。

实战步骤

# ============ 第一步:查看当前状态 ============
git status
git branch
# 确认在 main 分支,确认工作区干净

# ============ 第二步:拉取最新代码 ============
git pull

# ============ 第三步:创建功能分支 ============
git switch -c feature/product-search
# 或 git checkout -b feature/product-search

# ============ 第四步:在分支上开发 ============
# ... 写代码中 ...
# 创建了 search.js,修改了 index.html

# ============ 第五步:查看修改 ============
git status
# On branch feature/product-search
# Changes not staged for commit:
#   modified:   index.html
# Untracked files:
#   search.js

git diff
# 查看具体改了什么

# ============ 第六步:提交代码 ============
git add index.html search.js
git commit -m "feat(search): 添加商品搜索功能

实现了基于关键字的商品搜索,支持模糊匹配。"

# ============ 第七步:紧急插播——线上出bug了! ============
# 搜索功能还没做完,不能提交
git stash save "搜索功能开发中-暂存进度"

# 切回 main 分支
git switch main

# 拉取最新代码
git pull

# 创建修复分支
git switch -c hotfix/search-crash

# 修复 bug...
git add .
git commit -m "fix(search): 修复搜索时输入特殊字符导致的崩溃"

# 推送到远程
git push -u origin hotfix/search-crash

# 切回 main,合并修复
git switch main
git merge --no-ff hotfix/search-crash
git push

# ============ 第八步:回到搜索功能开发 ============
git switch feature/product-search

# 恢复之前的工作进度
git stash pop

# 继续开发搜索功能...
git add .
git commit -m "feat(search): 完成搜索结果分页功能"

# ============ 第九步:推送功能分支 ============
git push -u origin feature/product-search

# ============ 第十步:切回 main,合并功能 ============
git switch main
git pull
git merge --no-ff feature/product-search
git push

# ============ 第十一步:清理已合并的分支 ============
git branch -d feature/product-search
git branch -d hotfix/search-crash
git push origin --delete feature/product-search
git push origin --delete hotfix/search-crash

9. 分支相关的常见错误和补救

不小心在错误的分支上改了代码

# 情况:你在 main 分支上改了代码,但应该在 feature/login 分支上改

# 方案1:用 stash 搬运(推荐)
git stash                           # 暂存修改
git switch feature/login            # 切到正确分支
git stash pop                        # 恢复修改

# 方案2:先提交,再 cherry-pick(第六篇会详细讲)
git add .
git commit -m "临时提交"
# 记下 commit 哈希值
git switch feature/login
git cherry-pick <commit-hash>
git switch main
git reset --hard HEAD~1             # 删除 main 上的那个提交

分支合并完忘了删除,越来越多

# 查看哪些分支已经合并了
git branch --merged

# 批量删除已合并的本地分支(保留 main 和 develop)
git branch --merged | grep -v "main\|develop" | xargs git branch -d

本篇小结

分支管理是 Git 中最核心也最强大的功能。掌握了分支,你就从"单机模式"进入了"多人协作模式"。

  • ✅ 理解了分支的本质:指向 commit 的指针
  • ✅ 学会了分支的创建、切换、删除
  • ✅ 掌握了 git stash 暂存工作进度
  • ✅ 理解了 git merge 的两种模式
  • ✅ 了解了 Git Flow、GitHub Flow 等分支策略
  • ✅ 完成了完整的实战演练

但分支合并还有一个重要的话题我们留到下一篇——冲突。当两个人修改了同一个文件的同一行代码时,Git 无法自动判断谁对谁错,就会产生冲突。这是新手最怕的情况之一,但其实只要理解了原理,冲突一点都不可怕。

下一篇,我们将专门讲解冲突解决和版本回退,教你如何从容应对各种"翻车"场景。我们下一篇见!