核心总结图
| 更改所在位置 | 推荐的撤销命令 | 主要作用 |
|---|---|---|
工作区 (改了但没 add) | git restore <file> | 放弃对某个文件的修改 |
暂存区 (已 add 但没 commit) | git restore --staged <file> | 将文件从暂存区撤下,但不影响工作区 |
本地仓库 (已 commit 但没 push) | git reset / git commit --amend | 修改或回退本地的提交记录 |
远程仓库 (已 push) | git revert | 创建一个“反向”的新提交来撤销 |
| 终极后悔药 (不小心搞砸了) | git reflog | 查看 HEAD 的移动记录,找回丢失的提交 |
1:文件在【工作区】,还没 git add
你修改了一个文件,但发现改错了,想恢复到上次提交时的样子。
- 命令:
git restore <file> - 示例:
git restore README.md(撤销对README.md的所有修改) - 什么情况下使用:
- 代码写崩了,想放弃所有本地修改。
- 不小心删错文件了,想从上次提交中恢复回来。
- ⚠️ 注意事项:
- 这个操作是危险的!它会永久丢弃你在工作区的所有修改,且无法通过 Git 找回。
- 在旧版 Git 中,这个操作使用
git checkout -- <file>,但checkout功能过于复杂,现在官方推荐使用更清晰的restore。
2:文件在【暂存区】,已经 git add 但还没 commit
你用 git add 把文件放到了暂存区,但突然发现:
a) 这个文件不应该被提交。
b) 文件里还有些内容需要修改,想先撤销暂存。
- 命令:
git restore --staged <file> - 示例:
git restore --staged config.js(将config.js从暂存区移出) - 什么情况下使用:
git add .时,不小心把临时文件、密码文件也加进去了。- 想把一个大文件拆分成几次提交,需要先把整个文件从暂存区撤出。
- ⚠️ 注意事项:
- 此命令只影响暂存区,你工作区里的文件修改会完整保留。
- 在旧版 Git 中,这个操作使用
git reset HEAD <file>,现在restore语义更明确。
3:提交在【本地仓库】,已经 commit 但还没 push
这是最复杂的情况,因为你操作的是已经生成的“历史记录”。
3.1 只想修改最后一次提交
你刚刚 commit,但发现:
a) Commit message 写错了。
b) 漏掉了一个文件没 add。
- 命令:
git commit --amend - 使用流程:
- 如果有漏掉的文件,先
git add <forgotten-file>。 - 然后执行
git commit --amend。 - Git 会打开编辑器让你修改 Commit message,保存并退出即可。
- 如果有漏掉的文件,先
- 什么情况下使用:
- 修复最近一次提交的拼写错误或补充信息。
- ⚠️ 注意事项:
--amend并非“修改”了上次提交,而是创建了一个包含新内容/新信息的新 Commit,并用它替换掉旧的 Commit。旧 Commit 会被丢弃。- 绝对不要对已经推送到公共分支(如
main,develop)的提交使用amend! 因为这会改变历史,导致团队其他成员的历史记录和你产生冲突。
3.2 想彻底撤销最近的几次提交
你连续做了几次 commit,发现方向完全错了,想回到某个历史版本。
- 命令:
git reset [--soft | --mixed | --hard] <commit-id> --soft: 最温柔。仅仅移动HEAD指针,你的代码改动会保留在暂存区。- 场景: ” 我提交了 3 次,但发现这 3 次应该合并成 1 次提交 “,你可以
git reset --soft HEAD~3,然后重新git commit。
- 场景: ” 我提交了 3 次,但发现这 3 次应该合并成 1 次提交 “,你可以
--mixed(默认模式): 移动HEAD指针,同时清空暂存区,你的代码改动会保留在工作区。- 场景: ” 我提交了,但想重新审视所有代码再决定怎么提交 “,你可以
git reset HEAD~1,然后重新git add和git commit。
- 场景: ” 我提交了,但想重新审视所有代码再决定怎么提交 “,你可以
--hard: 最粗暴。移动HEAD指针,同时清空暂存区和工作区。所有代码改动都会被彻底删除。- 场景: ” 这几次提交完全是垃圾,我不要了,彻底滚蛋!”
- 示例:
git reset HEAD~1(默认 mixed 模式,撤销最后 1 次提交,代码保留在工作区)git reset --hard abc5021(彻底回退到abc5021这个版本,之后的所有修改全部丢弃)
- ⚠️ 注意事项:
git reset --hard是 Git 中最危险的命令之一,会永久删除你的工作,使用前请三思。- 和
amend一样,reset会改写历史。绝对不要对已经推送到公共分支的提交使用reset!
4:提交在【远程仓库】,已经 push
这是最严重的情况。你把一个错误的提交推送到了团队共享的分支。此时严禁使用 git reset 或 git commit --amend,因为这会 “force push” (强制推送),搞乱所有人的仓库。
- 命令:
git revert <commit-id> - 工作原理:
revert不会删除或修改历史。它会创建一个新的 Commit,这个新 Commit 的内容恰好是指定 Commit 的反向操作。比如你revert了一个添加了代码的 Commit,那么这个新 Commit 就会把那些代码删除。 - 示例:
git revert abc5021(创建一个新提交,用来撤销abc5021这次提交所做的所有更改) - 什么情况下使用:
- 线上版本出现 Bug,需要紧急撤销某次引入问题的合并或提交。
- 撤销已经推送到公共分支的错误提交。
- ⚠️ 注意事项:
- 这是唯一推荐的、用于撤销公共历史的安全方式。
- 它保留了完整的提交历史,所有人都知道“这里曾经犯过错,然后被修正了”。
- 执行
revert时可能会产生冲突,因为后续的修改可能依赖于你想要撤销的那个提交。如果出现冲突,需要手动解决后再次提交。
5: 终极后悔药:git reflog
如果你不小心执行了 reset --hard,或者 amend 了一个不该动的提交,感觉世界末日了,别慌!
- 命令:
git reflog - 作用:
reflog记录了你本地仓库HEAD指针的所有移动历史,包括每一次commit,reset,amend,merge等操作。它就像一个飞行黑匣子。 - 使用流程:
- 运行
git reflog,你会看到一个操作列表,每一行都有一个HEAD@{n}的索引和一个 Commit ID。 - 找到你误操作之前的那个状态,记下它的 Commit ID (例如
abc5021)。 - 执行
git reset --hard abc5021,你的仓库就能奇迹般地恢复到那个状态!
- 运行
- ⚠️ 注意事项:
reflog只存在于你的本地仓库,不会被推送到远程。reflog中的记录有过期时间(默认 90 天),所以这是紧急救援措施,不是常规操作。
总结
- 分清界限:先想清楚你的修改在哪一步(工作区、暂存区、本地库、远程库)。
- 本地操作要谨慎:在本地(未
push)时,reset和amend很强大,但reset --hard要格外小心。 - 远程操作要安全:一旦
push到公共分支,永远优先考虑git revert,它不会改写历史,对团队协作最友好。 reflog是你的救命稻草:当你搞砸了本地历史时,记得reflog可以帮你找回几乎一切。