讲解
老教程里的 git checkout 是个「多面手」:既能切换分支,又能还原文件,还能切换到历史提交——一个命令三种用途,新手极易混淆。Git 2.23(2019 年)把它拆成了两个职责单一的命令:git switch 专职切换分支,git restore 专职还原文件。现在的新代码都应该用这两个,checkout 只需要认得就行(老脚本和文档里还大量存在)。
git restore 是日常后悔药:git restore 文件 丢弃工作区里未暂存的修改(把文件还原成暂存区/最近提交的样子);git restore --staged 文件 把已暂存的改动撤出暂存区(文件内容不动,只是取消 add);两者组合就能完整撤掉一个还没提交的改动。更强大的是 git restore --source 提交或标签 文件——从任意历史版本把文件取回来,误删的文件、想找回的旧实现都靠它。要注意:丢弃工作区修改是不可逆的,没提交过的新内容丢了就是丢了。
git switch 除了切分支,还能进入「分离 HEAD」状态:git switch --detach 某个提交 把 HEAD 直接指向一个历史提交(而不是分支),此时可以随便查看、试验那个时间点的代码。这个状态下做的提交不属于任何分支,切走之后就找不到了(除非记下哈希或建分支)。看完想回去,git switch 分支名 即可;想在历史点上继续开发,git switch -c 新分支 从那里岔出来。
示例
git switch -c experiment
echo "实验代码" > exp.txt
git add exp.txt
git commit -qm "feat: 实验性功能"
git switch main
echo "不想要的修改" >> app.js
git status --short
git restore app.js
git status --short
echo "准备提交的内容" >> docs.txt
git add docs.txt
git restore --staged docs.txt
git status --short
git restore docs.txt
echo "v2" >> app.js
git add app.js
git commit -qm "feat: app v2"
git restore --source v0.1.0 app.js
git diff --stat
git restore app.js
git switch --detach v0.1.0
git log --oneline -1
git switch main
演示覆盖四种场景:丢弃工作区修改、撤出暂存区、从标签 v0.1.0 取回 app.js 的旧版本、分离 HEAD 查看历史。最后切回 main,一切如常。
常见坑
- restore 丢弃了没提交的新文件内容:restore 还原的是「已跟踪文件的修改」,它帮不了未跟踪文件,但对已跟踪文件的未提交修改是毁灭性的——丢之前先确认没有心血在里面。
- 想撤出暂存却丢了工作区改动:--staged 只动暂存区;不加参数才动工作区。两个作用域记反了会丢代码。
- 在分离 HEAD 上提交后直接切走:提交还在但没有任何分支指向它,git switch 时会警告。要么立刻建分支,要么记下哈希。
- 继续在老教程里学 checkout:checkout 依然兼容,但新学就按 switch/restore 分工记,概念会清晰得多。
小结
switch 管分支(含 --detach 看历史),restore 管文件(工作区、--staged 暂存区、--source 历史版本)。这对命令替代了 checkout 的混乱语义。下一章把分支上的工作合并回来:merge。