Git restore 怎么撤销:先选来源,再选暂存区或工作区
文件改错时,直接搜索一条“撤销命令”很危险,因为你可能只想取消暂存,也可能想丢弃工作区修改。Git restore 的关键有两个:从哪里取内容,写到哪个位置。本文在 Linux、Bash 5.2.37、Git 2.52.0 上建立一次性仓库;restore 自 Git 2.23 起提供,示例不会接触当前项目。
AI生成概念图:三个存放区域之间,仅将选定来源的内容送到目标区域。仅作概念说明,不代表实际界面或实测数据。
故意建立三个不同版本
HEAD 是最近一次提交的快照,暂存区是下一次准备提交的内容,工作区是磁盘上正在编辑的文件。下面先提交 base,再把 staged 放进暂存区,最后只在工作区写入 working。三个位置各不相同,才能判断一次恢复究竟改了什么。示例配置仅写进临时仓库。
( set -eu work=$(mktemp -d) trap 'rm -rf -- "$work"' EXIT git init -q "$work/repo" cd "$work/repo" git config user.name Demo git config user.email demo@example.invalid git config commit.gpgsign false git config core.hooksPath /dev/null printf 'base\n' > note.txt git add note.txt git commit -qm base printf 'staged\n' > note.txt git add note.txt printf 'working\n' > note.txt git status --short git restore --worktree -- note.txt test "$(cat note.txt)" = staged printf 'working\n' > note.txt git restore --staged -- note.txt test "$(git show :note.txt)" = base test "$(cat note.txt)" = working git status --short git restore --source=HEAD --staged --worktree -- note.txt test "$(cat note.txt)" = base test -z "$(git status --porcelain)" printf 'clean: base\n' )
第一次简短状态输出为 MM note.txt:左侧表示暂存区相对 HEAD 有变化,右侧表示工作区相对暂存区也有变化。读取状态时保留前导空格很重要;若把显示结果自动去空格,后面的“仅工作区修改”会失去位置含义。
只恢复工作区,默认来源是暂存区
第一次 restore 明确写了 worktree,没有指定 source。因此工作区变成暂存区中的 staged,而不是 HEAD 中的 base。示例用断言立即核对文件内容。这也解释了为什么“我刚运行恢复命令,文件却没有回到上次提交”:默认来源取决于你是否选择了暂存区目标。
如果一个文件部分已暂存、部分尚未暂存,这种操作会覆盖尚未暂存的部分。运行前先查看普通 diff;它展示工作区与暂存区的差异。需要留住的内容应先另存或提交到合适位置,不能把恢复命令本身当作自动备份。对从未记录的修改,Git 未必有可找回的对象。
取消暂存并不删除工作区内容
示例重新把工作区写成 working,然后执行 staged 恢复。此时默认来源转为 HEAD,暂存区回到 base,工作区仍为 working。输出变成前面一个空格、后面一个 M。它表达的是下一次提交不再包含已暂存版本,磁盘上的编辑仍然存在。
检查取消暂存是否符合预期,应同时看缓存差异和普通差异。只看到一条命令没有报错,无法证明所需内容仍在正确位置。若本来只想从下一次提交中移除修改,就不要顺手再加 worktree 选项,否则目标范围发生了实质变化。
来源和两个目标都写出来更容易审阅
最后一条恢复明确从 HEAD 取内容,同时写入暂存区和工作区,所以两处都变成 base,状态为空。这会覆盖示例文件的未提交内容;教程里可以这样做,是因为仓库刚创建且数据专用于实验。在真实仓库里,应先确认源提交、路径以及两个目标的差异。
双短横线结束选项解释,后面给出单个明确路径。不要为省打字把整个项目通配进去。还要注意,某个已跟踪路径如果在来源树里不存在,恢复可能移除该路径以匹配来源。恢复文件不会创建一条撤销历史提交的新提交;若目标是公开历史中的反向变更,应另行评估 revert。
把操作前后的三个内容写在纸上,通常比死记命令更可靠。来源回答“拿哪个版本”,目标回答“改变哪一层”,路径回答“影响哪些文件”。每次仅改变必要的组合,再检查状态和实际内容,恢复行为就能被解释,也能被验证。


