CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Git/GitHub 入门实战/课时/Git 进阶
RawBlame
课时目录12 节

Git/GitHub 入门实战

  1. 01Git 基础概念
  2. 02基本 Git 操作
  3. 03Git 进阶
  4. 04GitHub 入门
  5. 05协作基础
  6. 06分支工作流
  7. 07Pull Request
  8. 08Issues 管理
  9. 09团队协作
  10. 10安全习惯
  11. 11路线图对照
  12. 12综合练习

Git 进阶

分支、合并与 stash。

30 分钟

Git 进阶

这一课你将能做到

  1. 用 git switch / git branch 创建、切换、删除分支,并理解 HEAD 指针
  2. 区分 fast-forward 合并与三方合并,会用 --no-ff 保留分支历史
  3. 用 git stash 临时存稿,用 git tag 打版本号,用 cherry-pick 挑提交

为什么要学

分支是 Git 的灵魂,也是它碾压 SVN 的根本原因:Git 的分支只是一个指向 commit 的指针(41 字节),创建一个分支的代价是「零」。这让我们可以为每个 bug、每个功能开一条独立分支,互不干扰地并行开发。

不理解分支模型,后面学的 GitHub PR、Code Review、Git Flow 全都立不住。而面试官问你「HEAD 是什么」「merge 和 rebase 区别」时,答的就是这一课的内容。

先建立图像

分支 = 指针,HEAD = 当前位置标记:

                main 分支
                  ▼
A ── B ── C ────── D
            \
             E ── F        ← feature 分支
                  ▲
                 HEAD(你正站在这里)

合并的两种形态:

【fast-forward】main 直接快进到 feature(没有合并 commit)
A─B─C─D  ─合并后─>  A─B─C─D─E─F   main 移到 F

【三方合并 / --no-ff】产生一个合并 commit M
A─B─C─D───M
      \  /
       E─F

--no-ff 强制走三方合并,好处是历史里能看出「这是一条功能分支」。

跟着做

步骤 1:创建并切换分支

git branch                      # 列出本地分支,* 号是当前
git switch -c feature/login     # 创建并切换(推荐新语法)
# 等价老命令:git checkout -b feature/login

# 在新分支上改代码、提交
echo "// 登录功能" >> src/Login.java
git add .
git commit -m "feat: 实现用户登录"

switch 是 Git 2.23 引入的新命令,专职「切分支」;restore 专职「改文件」,把老 checkout 的职责拆开了。

步骤 2:查看分支图

git log --oneline --graph --all
# * 3f4a2b1 (HEAD -> feature/login) feat: 实现用户登录
# * d1e5c6a (main) fix: 修复首页空指针

--graph --all 让你同时看到所有分支的分叉结构。

步骤 3:合并分支(fast-forward)

git switch main
git merge feature/login
# Fast-forward
#  src/Login.java | 1 +

如果 main 在你开发期间没有新提交,Git 直接把 main 指针快进到 feature 最新位置,不产生合并 commit。

步骤 4:强制三方合并(保留分支痕迹)

git switch main
git merge --no-ff feature/login -m "merge: 合入登录功能"

团队开发推荐 --no-ff,因为历史里能清楚看到「这一坨是一个功能」。

步骤 5:删除分支

git branch -d feature/login     # 安全删除(已合并)
git branch -D feature/login     # 强制删除(未合并也删,危险)

步骤 6:临时存稿 stash

正在改代码,线上突然报 bug 要你切回 main 处理?不想 commit 半成品:

git stash                       # 把当前改动收起来
git switch main                 # 去修 bug ...
git switch feature/login
git stash pop                   # 恢复刚才的改动

常用变体:git stash list 看列表、git stash show -p 看内容、git stash drop 丢弃。

步骤 7:打标签与 cherry-pick

# 给当前 commit 打版本号
git tag -a v1.0.0 -m "首个正式版"
git tag                         # 列出所有 tag
git push origin v1.0.0          # 推送标签到远程

# 把别的分支的某个 commit 单独挑过来
git cherry-pick 3f4a2b1

cherry-pick 常用于「这个修复只要那一个 commit,不要整条分支」。

讲清楚要点

  1. 分支只是指针:git branch xxx 只是创建了一个 41 字节的文件指向当前 commit,没有任何文件拷贝。这就是 Git 分支「廉价」的本质。
  2. HEAD 是「你当前在哪」的标记:通常 HEAD 指向某个分支名,分支名再指向 commit。git switch 就是移动 HEAD。
  3. fast-forward vs 三方合并:能快进就快进(无新 commit);如果 main 和 feature 都各自前进了,Git 会生成一个合并 commit 把两条线拧一起(三方合并)。
  4. stash 是栈结构:先进后出。pop 取出并删除,apply 只取出不删除,可同时存多份。
  5. tag 是打在某个 commit 上的永久铭牌:和分支的区别是分支会随提交前移,tag 永远不动,常用于标记发布版本。

你可能会懵的地方

  • git switch 和 git checkout 到底用哪个? 新代码统一用 switch(切分支)和 restore(改文件),语义清晰。checkout 是老命令,一个命令干两件事,容易混淆,但所有老教程都在用它,你得认识。

  • fast-forward 是不是「丢了分支信息」? 是。历史变成一条直线,看不出哪些 commit 属于哪个功能。团队开发建议 git merge --no-ff,强制生成合并 commit。

  • detached HEAD 是什么鬼? 当 HEAD 不指向任何分支、直接指向某个 commit 时(比如 git switch --detach a1b2c3d 或切到 tag),就进入「游离头指针」状态。此时提交的 commit 没有分支引用,切走后可能丢。解决:立刻 git switch -c 新分支 给它安个家。

  • stash 能跨分支用吗? 能。stash 是全局的,不绑定分支。在 A 分支 stash,切到 B 分支 pop,改动会落到 B 的工作区。

  • tag 和 branch 有什么本质区别? branch 是可移动的指针,tag 是固定在某个 commit 上的名字。branch 用来开发,tag 用来标记里程碑。

错法对照

错法问题正解
在 main 上直接改代码污染主干,回滚困难任何改动都先 switch -c feature/xxx
用 -D 强删未合并分支未合并工作丢失默认用 -d,确认无用再 -D
git stash 后忘记 pop改动「消失」了git stash list 随时查,处理完立刻 pop
detached HEAD 下直接提交提交没人引用,切走就丢先 git switch -c 新分支 再提交
打完 tag 忘记 push远程看不到版本git push origin --tags

卡点急救

  1. git switch 报错「Your local changes would be overwritten」:当前改动与目标分支冲突。先 git stash 收起来,切换后再 git stash pop;或先 commit。
  2. 误删了分支:git reflog 找到该分支最后一次 commit 的哈希,然后 git branch 分支名 哈希 即可复活。
  3. detached HEAD 下已经提交了东西:立刻 git switch -c temp-save 把当前位置固定成分支,再决定合到哪里。

面试常问

  • HEAD 是什么? HEAD 是一个指针,指向「当前所在的分支」(更精确说是指向当前分支名)。git switch 移动 HEAD,git commit 让 HEAD 指向的分支前进一格。detached HEAD 就是 HEAD 直接指向 commit 而非分支。

  • git merge 的 fast-forward 和三方合并区别? 目标分支自分支点之后没有新提交时,Git 直接快进指针(无合并 commit);如果双方都前进了,Git 找共同祖先做三方合并,生成一个合并 commit。--no-ff 可强制后者。

  • git cherry-pick 什么时候用? 当另一个分支上有某个 commit(比如热修复)你需要,但不想合并整条分支时,用 cherry-pick 把那个 commit 单独复制到当前分支。注意它生成的是新 commit(哈希不同)。

自测三问

  1. 创建分支的开销为什么接近零?分支文件存在哪?
  2. fast-forward 什么时候发生?怎么强制禁用它?
  3. git stash pop 和 git stash apply 的区别?

小结一句话

分支是廉价指针、HEAD 是当前位置,掌握 switch / merge / stash / tag / cherry-pick,你就拥有了并行开发的超能力。

延伸

  • Pro Git:分支
  • 下一课:GitHub 入门——把本地仓库推上云端,理解 origin / remote / push / pull。
加载本节练习…
← 上一课基本 Git 操作下一课 →GitHub 入门