Git 分支 — branch / checkout / switch

分支是 Git 最强大的特性,也是它彻底击败 SVN 的核心原因。理解了分支,你才能放心地"并行开发多个功能而不互相干扰"。这一章讲清楚分支的本质、怎么创建切换删除、以及团队命名的最佳实践。

1. 分支的本质:就是一个指针

很多新手觉得分支很神秘,其实它的本质简单得不能再简单:分支就是一个指向某个提交的可移动指针

正因为分支这么轻,你才敢一天开十个分支:每个功能、每个 bug 一个分支,互不干扰。

2. 创建与切换分支

# 分支:Git 的灵魂特性
# 默认分支以前叫 master,现在社区约定叫 main

# 查看所有分支(* 表示当前所在)
git branch
# 输出:
#   feature-login
# * main
#   dev

# 查看所有分支 + 远程分支 + 最新提交
git branch -a -v

# 创建分支(但不切换过去)
git branch feature-login

# 切换分支:新版推荐 switch(语义清晰)
git switch feature-login

# 老命令 checkout 也能切换,但容易和"撤销"混淆
git checkout feature-login

# 创建并切换,一步搞定
git switch -c feature-cart     # 新写法(推荐)
git checkout -b feature-cart   # 老写法

关于 checkoutswitch:老命令 git checkout 既能切换分支、又能撤销文件改动,语义混乱。Git 2.23(2019 年)引入了 switch(切换分支)和 restore(撤销改动)两个新命令,职责清晰。新项目推荐用新命令,但 checkout 仍然有效,老教程/老脚本里到处都是。

3. 在分支上开发

切换到 feature 分支后,你做的所有 add / commit 都只影响这个分支,main 分支完全不受影响。这就是"并行开发"的奥秘:

# 在 feature 分支上正常开发,该 add 就 add,该 commit 就 commit
git switch -c feature-login
echo "<form>登录表单</form>" > login.html
git add login.html
git commit -m "feat: 添加登录页"

echo "继续完善登录"
echo "校验逻辑" >> login.html
git add login.html
git commit -m "feat: 登录页添加校验"

# 回到 main 分支,工作区会变回 main 的状态(login.html 消失了!)
git switch main
ls                  # 看不到 login.html,因为它在 feature 分支上

# 切回 feature 分支,login.html 又回来了
git switch feature-login
ls                  # login.html 又出现了

注意切换分支时,Git 会自动切换工作区的文件。如果当前分支有未提交的改动,Git 可能会阻止你切换(提示 "Your local changes would be overwritten")——这时要么先 commit,要么用下一篇讲的 git stash 暂存。

4. 删除与重命名分支

分支合并完用不上后,应该及时删掉,保持分支列表清爽:

# 删除分支(开发完合并后的清理)
git branch -d feature-login       # 安全删除(已合并才允许)
git branch -D feature-login       # 强制删除(未合并也删,慎用!)

# 重命名分支
git branch -m old-name new-name   # 重命名当前分支
git branch -m main                # 把当前分支改名为 main

# 删除远程分支
git push origin --delete feature-login

# 把本地分支推到远程(建立追踪关系)
git push -u origin feature-login
# 之后在这个分支上 git push / git pull 不用带参数

-d(小写)是安全删除,只允许删已合并的分支,防止误删工作;-D(大写)是强制删除,未合并的提交会丢失(虽然能通过 reflog 找回,但麻烦)。新手优先用小写。

5. HEAD 指针

HEAD 是 Git 里一个特殊指针,表示"你当前所在的位置"。理解它能解释很多 Git 的行为:

# HEAD 是一个特殊指针,指向"当前所在的位置"
# 通常 HEAD 指向某个分支名,分支名再指向某个提交

# 查看当前 HEAD 指向哪
cat .git/HEAD
# 输出: ref: refs/heads/main
# 表示 HEAD 指向 main 分支

# detached HEAD:HEAD 直接指向某个提交(而不是分支名)
git switch --detach a1b2c3d
# 此时你处于"游离头指针"状态,提交不会属于任何分支
# 适合:临时看一下历史某个版本
# 注意:这种状态下 commit 容易丢失,要小心
#       想保留就 git switch -c new-branch 给它建个分支

通常 HEAD → 分支名 → 提交,这是一条链。当你 switch 时,HEAD 改指向新分支名。如果你 switch --detach 直接到某个提交,HEAD 就"游离"了——这种状态下提交不属于任何分支,容易丢失,适合临时查看历史版本。

6. 分支命名约定

团队协作时,分支名要有统一规范,这样每个人一看分支名就知道它在干什么:

# 分支命名约定(团队规范,让历史一目了然)
#
# 常见前缀:
#   feature/xxx    新功能
#   bugfix/xxx     修 bug
#   hotfix/xxx     紧急修复(直接基于生产分支)
#   release/xxx    发布分支
#   chore/xxx      杂项(改构建、依赖)
#   docs/xxx       文档
#
# 示例:
#   feature/user-avatar
#   bugfix/cart-negative-quantity
#   hotfix/login-crash
#   release/v2.1.0
#
# 命名建议:
#   - 用英文小写 + 连字符(不用下划线/空格)
#   - 名字能说明"做什么",不要太长
#   - 可加工单号:feature/JIRA-123-user-avatar

最佳实践

← 上一篇 Git 基础命令

下一篇 Git 合并与冲突

✈️💬