背景与动机
Git 撤销类命令最容易让人紧张,因为它们有的只是取消暂存,有的会丢弃工作区修改,有的会改写提交历史。
先记住一个判断顺序:
我要处理的是工作区、暂存区、本地提交,还是已经推送的提交?位置不同,应该使用的命令不同。
核心原理拆解
1. git stash:临时保存未提交修改
git stash 用来临时保存未提交的工作区变更:
git stash常见场景是:你正在写一半,突然需要切分支修一个紧急问题,但当前改动还不适合提交。
查看 stash 列表:
git stash list恢复最近一次 stash,并从 stash 列表中删除:
git stash pop恢复但保留 stash 记录:
git stash apply带说明保存:
git stash push -m "work in progress: login form"注意:stash 是临时工具,不适合长期保存重要代码。重要变更应该提交到分支。
2. git restore:恢复工作区或取消暂存
丢弃工作区中某个文件的未暂存修改:
git restore <file>把已经暂存的文件移出暂存区,但保留工作区修改:
git restore --staged <file>这两个命令影响范围不同:
git restore <file>:丢弃工作区修改。git restore --staged <file>:只取消暂存,不丢修改。
执行 git restore <file> 前要确认这个文件的未提交修改不需要保留。
3. git reset:移动分支指针或撤销提交
git reset 常用于移动当前分支指针,或者撤销提交。
撤销最近一次提交,但保留修改到工作区:
git reset --mixed HEAD~1撤销最近一次提交,并保留修改到暂存区:
git reset --soft HEAD~1彻底丢弃最近一次提交和修改:
git reset --hard HEAD~1--hard 会丢弃工作区内容,风险很高。执行前必须确认没有需要保留的改动。
4. git revert:用新提交反向撤销
git revert 用一个新的提交来反向撤销某个历史提交:
git revert <commit-id>它不会改写历史,因此更适合已经推送到远程、多人共享的分支。
简单区分:
- 本地还没推送,想整理历史:可以考虑
reset。 - 已经推送并被别人基于它开发:优先考虑
revert。
常见工作流示例
临时切分支处理别的事情
git status -sbgit stash push -m "work in progress"git switch main
# 处理其他任务
git switch feature/currentgit stash pop取消暂存但保留修改
git restore --staged <file>git status -sb这个操作只把文件从暂存区移回工作区,不会丢掉内容。
撤销本地最近一次提交
git reset --mixed HEAD~1这个操作会撤销提交,但保留文件修改,适合“提交太早了,还想继续改”的场景。
撤销已经推送的提交
git revert <commit-id>git push它会生成一个新的反向提交,不破坏共享历史。
常见陷阱
1. 把 restore 和 restore —staged 搞混
git restore --staged <file> 不丢修改,只取消暂存。
git restore <file> 会丢弃工作区修改。
2. 随手使用 reset —hard
git reset --hard 会同时移动提交指针并丢弃工作区内容。除非非常确定,否则不要把它当成普通清理命令。
3. 在共享分支上用 reset 改写历史
已经推送并被别人使用的提交,优先用 revert 撤销。reset 更适合本地尚未共享的历史整理。
4. 把 stash 当长期备份
stash 适合临时过渡,不适合长期保存重要代码。长期工作应该放到分支和 commit 里。
一句话总结
撤销前先判断目标位置:工作区用 restore,临时切换用 stash,本地历史可用 reset,共享历史优先用 revert。