Git 分支 — branch / checkout / switch
分支是 Git 最强大的特性,也是它彻底击败 SVN 的核心原因。理解了分支,你才能放心地"并行开发多个功能而不互相干扰"。这一章讲清楚分支的本质、怎么创建切换删除、以及团队命名的最佳实践。
1. 分支的本质:就是一个指针
很多新手觉得分支很神秘,其实它的本质简单得不能再简单:分支就是一个指向某个提交的可移动指针。
- 每次
commit,当前分支的指针就向前挪一格,指向新的提交。 - 创建分支,就是新建一个 41 字节的指针文件(几乎零开销)——这是 Git 区别于 SVN(分支要复制整个目录)的最大优势。
- 切换分支,就是让
HEAD指向另一个分支名,同时把工作区的文件换成那个分支的内容。
正因为分支这么轻,你才敢一天开十个分支:每个功能、每个 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 # 老写法关于 checkout 和 switch:老命令 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最佳实践
- 主分支(main)始终保持可发布:任何新功能都在 feature 分支开发,完成后再合并。这样 main 随时能上线,不会因为"开发到一半"而瘫痪。
- 分支生命周期要短:一个 feature 分支最好 1~3 天内合并,拖太久会和 main 差太远,合并冲突会爆炸。
- 勤拉取主干:开发期间经常
git fetch+ 把 main 的最新改动合并进来,避免最后大冲突。 - 一个分支只做一件事:不要在 feature/login 分支里顺手改购物车,拆成两个分支才好评审、好回退。
← 上一篇 Git 基础命令
下一篇 Git 合并与冲突 →