编程 git checkout 拆成两条命令:Git 2.23 的 git switch / git restore 选项行为与迁移对照

2026-10-14 23:42:57

git checkout 拆成两条命令:Git 2.23 的 git switch / git restore 选项行为与迁移对照

Git 2.23.0(2019-08-16)引入 git switch 与 git restore,把原本 git checkout 一肩挑的「切换分支」和「检出文件内容」两类职责拆开。

git checkout 的三种语义

同一个命令承担三件事:

git checkout               # 切分支
git checkout -b        # 创建并切换到新分支
git checkout  --
# 检出文件/路径:丢弃工作区改动,
# 或从某个 commit/tag 取文件覆盖

问题在于第三种用法和第一种的动词形式几乎一样,误操作(本想切分支却覆盖了工作区)在命令行补全下很容易发生。拆开的两条命令各自只做一件事。

git switch —— 只管分支切换

git switch [] [--no-guess]
git switch [] --detach []
git switch [] (-c|-C)  []
git switch [] --orphan

关键行为与选项:

  • 切分支不要求干净的索引和工作区;但若操作会导致本地改动丢失则中止,除非给 --discard-changes 或 --merge。
  • -c / --create :创建并切换,是「事务性」的,等价于 git branch + git switch ;失败时(例如该分支已被其它 worktree 占用)分支不会被创建/重置。
  • -C / --force-create :类似 -c,但若分支已存在则重置到 ``,等价于 git branch -f + git switch 。
  • -d / --detach []:切到某个 commit 做检查/实验(分离 HEAD)。
  • @{-N} 可引用第 N 次用 switch/checkout 切到的分支/提交;- 等同于 @{-1},用于在两条分支间快速往返或撤销误切。
  • --guess / --no-guess:`` 本地不存在但在某个远端恰有同名跟踪分支时,等价于 git switch -c --track /。--guess 是默认值,可用 checkout.guess=false 关掉。
  • -m / --merge:有会冲突的本地改动时先 autostash,切换后重新应用;仍有冲突则存入 stash 列表。
  • -f / --discard-changes:即使索引/工作区与 HEAD 不同也继续,丢弃本地改动。
  • --orphan :创建无父的 unborn 分支并移除所有已跟踪文件。
  • -t / --track[ (direct|inherit) ]:建新分支时设置 upstream。
  • 还有 --ignore-other-worktrees、--recurse-submodules、-q/--quiet、--progress。

git restore —— 只处理路径内容

git restore [] [--source=] [--staged] [--worktree] [--]
...
git restore [] [--source=] [--staged] [--worktree] --pathspec-from-file= [--pathspec-file-nul]
git restore (-p|--patch) [] [--source=] [--staged] [--worktree] [--] [
...]

关键行为与选项:

  • 用 restore source 的内容恢复工作区指定路径;若路径已跟踪但在 source 中不存在,会被删除以匹配 source。
  • 默认恢复位置取决于选项:给 --staged 时从 HEAD 恢复索引,否则从索引恢复工作区。用 --source= 从其它 commit/branch/tag 恢复。
  • -W/--worktree 与 -S/--staged 指定恢复位置;两者都不给默认恢复工作区;两者都给则同时恢复索引和工作区。
  • -s / --source=:从给定 tree 恢复;该选项不支持与 --ours/--theirs/-m 同用(后三者只用于从索引恢复)。
  • --ours/--theirs、-m/--merge、--conflict=(merge|diff3|zdiff3)、--ignore-unmerged:处理未合并(冲突)路径。
  • -p/--patch 交互式挑 hunk;--pathspec-from-file / --pathspec-file-nul。
  • --overlay/--no-overlay:默认 no-overlay,会删除 --source 中没有的已跟踪文件以精确匹配 source。
  • 另有 --recurse-submodules、--ignore-skip-worktree-bits、-q/--quiet。

迁移对照

旧写法新写法
git checkoutgit switch
git checkout -bgit switch -c
git checkout -- (丢弃工作区改动)git restore
git checkout --git restore --source=
git reset (取消暂存)git restore --staged
git checkout . / git checkout -- .git restore .

官方示例

switch 侧:

git switch master
git switch -m mytopic          # 本地改动被 autostash 后带过去
git switch -                   # 回到上一个分支
git switch -c fixup HEAD~3
git switch --detach HEAD~3
git switch -c good-surprises   # 给实验成果命名

restore 侧:

git restore --source master~2 Makefile
git restore hello.c
git restore '*.c'
git restore .
git restore :/
git restore --staged hello.c
git restore -s@ -SW hello.c    # 等价 --source=HEAD --staged --worktree

为什么 git 不删掉 checkout

git checkout 没有被废弃:

  • 脚本与历史兼容。大量现有脚本、CI 配置、文档都在用它。
  • checkout 仍能一条命令同时操作索引与工作区,而 restore 需要显式写 --staged --worktree。
  • checkout 还能直接切到 commit 并附带路径等混合操作,switch 与 restore 都不覆盖这种组合。

新老 Git 的分界线是 2.23.0:这之前没有 switch/restore,写脚本或 CI 要判版本,否则在旧环境上会直接报未知命令。

相关配置项

  • checkout.defaultRemote
  • checkout.guess
  • checkout.workers:默认 1,小于 1 时按逻辑核数
  • checkout.thresholdForParallelism:默认 100 个文件

文档:git-switch 、git-restore。

复制全文 生成海报 新命令 Git Shell 版本控制 命令行

推荐文章

程序员茄子在线接单