git restore --staged 是 git 2.23+ 撤回暂存区的标准做法,只移出暂存区文件,不改动工作区;老版本用 git reset head ,禁用语义模糊的 git checkout。

文件已 git add 但还没 git commit,想撤回暂存区?直接用 git restore --staged <file></file>,这是 Git 2.23+ 的标准做法;老版本用 git reset HEAD <file></file>,别碰 git checkout ——它在现代 Git 里语义模糊,容易误删工作区内容。
撤单个文件:用 git restore --staged 最安全
这是当前推荐方式,只影响暂存区,完全不碰工作区文件内容:
-
git restore --staged README.md:把 README.md 从暂存区移出,工作区保持原样 - 如果文件名含空格或特殊字符,加引号:
git restore --staged "src/utils/log helper.js" - 执行后运行
git status,会看到该文件从 “Changes to be committed” 区块移到 “Changes not staged for commit” 区块 - 注意:
--staged不能缩写为-s(Git 不支持),必须写全
批量撤回:路径通配与目录处理要小心
想一次清掉某个目录下所有暂存文件?通配符能用,但有边界限制:
监控一个或多个 GitCode 仓库的 PR,通过 OpenClaw Gateway 自动执行 AI 审查,发布 PR 评论,并发送钉钉和企业微信通知。
-
git restore --staged src/:撤回src/下所有已暂存文件(不含子目录里新增的未跟踪文件) -
git restore --staged "src/**/*.js":shell 展开后生效,需确保你的 shell 支持**(zsh/bash 4.3+),否则用git ls-files -m src/ | grep '\.js$' | xargs git restore --staged - 别用
git restore --staged .撤整个仓库——它会把所有暂存文件都移出,包括你可能想保留的修改 - 如果执行后发现漏了某些文件,检查是否被
.gitignore掩盖:被忽略的文件不会出现在git status中,自然也不会被restore处理
老 Git 版本(git reset HEAD
低于 Git 2.23 的环境(比如 CentOS 7 自带的 Git 1.8.3),git restore 命令不存在,必须用传统方式:
-
git reset HEAD README.md:效果等同于git restore --staged README.md -
git reset HEAD -- src/:双横杠明确分隔选项和路径,避免路径名被误认为参数 - ⚠️ 千万别写成
git reset README.md(缺HEAD)——Git 会默认指向当前分支头,但语义不清,且在分离头指针状态下行为难预测 - 这个命令在 Git 2.23+ 依然可用,但属于“兼容性写法”,新项目建议统一迁移到
restore
为什么坚决不用 git checkout -- <file></file>?
很多老文档还教这个,但它在现代 Git 中风险极高:
-
git checkout -- README.md实际是“丢弃工作区修改”,不是“撤销暂存”——它会把工作区文件重置为HEAD版本,连你刚改的几行代码都丢了 - Git 2.23 引入
git restore正是为了拆分checkout的混乱职责:restore管“还原内容”,switch管“切换分支” - 即使你只想撤暂存,输错成
git checkout --staged也会报错,而git restore --staged参数校验严格,输错直接提示可用选项 - 如果你正在用 Git GUI 或 VS Code 内置终端,确认下 Git 版本:
git --version;低于 2.23 就别在教程里抄restore示例,否则命令根本不存在
真正容易被忽略的是:暂存区本身没有“状态快照”,它只是索引(index)中的一组文件哈希引用。所以所谓“撤回”,本质是让索引里的条目重新指向 HEAD 对应的树对象——这意味着,如果 HEAD 里根本没有那个文件(比如你 add 的是全新文件),撤回后它就变成“未跟踪”状态,git status 会显示为红色,不是消失。










