Git 如何把文件恢复到指定的历史版本
用 git restore --source 指定历史提交恢复单文件;加 --staged --worktree 可同时更新暂存区与工作区。说明与 checkout、revert 的区别及如何撤销恢复。
一句话回答:git checkout <提交号> -- <文件路径> 把该文件还原到指定提交的内容(Git 2.23+ 等价新写法:git restore --source=<提交号> --staged --worktree -- <文件>)。还原结果同时写入工作区和暂存区,其他文件不受影响,确认后正常 commit 即可形成一次"回滚该文件"的新提交。
执行前先备份该文件的未提交改动:下面命令会覆盖它们。只希望先改工作区以便检查时,用 git restore --source=<提交号> -- <文件>,不加 --staged;它与同时更新两个区域的 checkout 用法不完全相同。
基本用法
# 还原到指定提交
git checkout abc1234 -- src/config.js
# 还原到"某个提交之前"的版本(^ 表示其父提交)
git checkout abc1234^ -- src/config.js
# 还原到某个标签时的状态
git checkout v1.2.0 -- src/config.js
# 查看差异再决定
git diff HEAD abc1234 -- src/config.js
执行后 git status 会显示该文件处于已修改状态,git diff --cached 能看到与当前版本的具体差异。
新写法(Git 2.23+)
git restore --source=abc1234 --staged --worktree src/config.js
restore 语义更明确(--source 指定来源版本),与 checkout 的还原文件用法等价。
与 revert 的区别
| 方式 | 效果 | 历史 |
|---|---|---|
checkout 提交 -- 文件 |
文件内容直接换成旧版 | 不产生新提交,等你手动 commit |
git revert 提交 |
生成"反向补丁"提交 | 自动产生新提交(针对整个提交而非单文件) |
回滚单个文件用 checkout/restore 最干净;要撤销整个提交的所有改动才用 revert。
配套技巧
git log --oneline -- src/config.js # 先查这个文件的变更历史,找到目标提交
git show abc1234:src/config.js # 不改文件,直接看那个版本的内容
常见问题(FAQ)
Q:还原后想撤销这次还原?
A:还没 commit 时 git restore --staged --worktree src/config.js(或 git checkout HEAD -- 文件)即可还原回当前版本;已 commit 后 HEAD 已包含恢复结果,不能靠再 checkout HEAD 撤销它;若该提交只做了本次恢复,可 git revert <该恢复提交>,否则从恢复前的明确提交再取回此文件并审核提交。
Q:文件名在历史中改过,能还原旧名字的内容吗?
A:可以。checkout 时用那个提交时刻的路径(旧名),会在工作区恢复该旧路径,不会自动映射到现在的新名字;要保留新名字,应先查看 git show <提交>:<旧路径>,备份后再将所需内容应用到新路径。配合 git log --follow -- 文件 追踪改名历史。
Q:批量还原整个目录到某版本?
A:git checkout abc1234 -- src/ 支持目录路径。大范围回滚也可以考虑 git revert 若干提交,语义更清晰。
核查依据
本文依据官方文档核对,示例未在实际业务环境运行;上线前请按部署版本、权限与数据范围验证。