Git 回退与撤销操作:reset/revert/checkout 的区别

小飞兽 Git 104 次阅读 2026-07-29

Introduction

在日常开发中,错误的提交、错误的修改或需要回退到某个历史版本是常见需求。Git 提供了三种主要的回退/撤销操作:reset、revert 和 checkout。虽然它们都可以用来"撤销"或"回退",但原理和使用场景完全不同。本文详细对比三者,帮助你选择正确的操作。

基础语法

# ===== git checkout(恢复文件/切换分支)======
git checkout -- <文件>           # 丢弃工作区修改,恢复到暂存区状态
git checkout HEAD -- <文件>      # 丢弃工作区和暂存区修改,恢复到 HEAD
git checkout <分支>              # 切换分支
git checkout -b <新分支>         # 创建并切换到新分支
git checkout HEAD~3 -- <文件>    # 将文件恢复到 3 个提交前的版本

===== git reset(回退提交/重置暂存区)======

git reset --soft HEAD~1 # 回退 1 个提交,保留更改在暂存区 git reset --mixed HEAD~1 # 回退 1 个提交,保留更改在工作区(默认) git reset --hard HEAD~1 # 回退 1 个提交,丢弃所有更改(危险!) git reset --hard <commit> # 回退到指定提交 git reset --merge HEAD~1 # 回退时保留暂存的合并冲突

===== git revert(创建新提交来撤销)======

git revert HEAD # 撤销最后一次提交 git revert <commit> # 撤销指定提交(生成新提交) git revert --no-commit HEAD~2 # 撤销倒数第2个提交(不自动提交) git revert -m 1 <merge-commit> # 撤销合并提交,需要指定主分支(1 或 2)

完整代码示例

# ===== Git 回退与撤销操作实战 =====

1. 初始化仓库

git init undo-demo && cd undo-demo echo "v1" > version.txt && git add . && git commit -m "v1" echo "v2" > version.txt && git add . && git commit -m "v2" echo "v3" > version.txt && git add . && git commit -m "v3" echo "v4" > version.txt && git add . && git commit -m "v4" git log --oneline

dcba v4

bcde v3

abcd v2

1234 v1

===== 场景1:工作区修改还没 add,想撤销 =====

echo "修改了但不想提交" >> version.txt git status

modified: version.txt (红色,工作区修改)

git checkout -- version.txt cat version.txt

v4(工作区修改已被丢弃)

===== 场景2:已经 add 但没 commit,想撤销 add =====

echo "临时修改" >> version.txt git add version.txt git status

modified: version.txt (绿色,已暂存)

git reset HEAD version.txt git status

modified: version.txt (红色,回到工作区)

注意:文件内容保留,只是从暂存区移除

===== 场景3:已经 commit,想回退到上一个版本 =====

--soft:保留暂存区和工作区所有修改

git reset --soft HEAD~1 git status

changes to be committed: version.txt(修改还在暂存区)

git commit -m "re-commit after soft reset"

===== 场景4:已经 commit,想完全回退(危险!)=====

git reset --hard HEAD~1 cat version.txt

v3(所有修改都被丢弃)

git log --oneline

bcde v3(v4 的提交已被删除)

===== 场景5:想撤销某个历史提交(保留历史)=====

git revert HEAD

会打开编辑器,输入撤销提交的信息

生成一个新提交来撤销 v3,效果上等于恢复到 v2

git log --oneline

efgh Revert "v3"

bcde v3

abcd v2

1234 v1

cat version.txt

v2(通过 revert 恢复到 v2 版本)

===== 场景6:用 checkout 恢复旧版本文件 =====

git checkout HEAD~2 -- version.txt

version.txt 内容变为 v2

注意:文件恢复,但 HEAD 没有移动

git status

modified: version.txt (工作区有修改)

git add . && git commit -m "restore to v2"

===== 场景7:revert 合并提交 =====

假设有一个 merge commit,需要指定保留哪条分支

git revert -m 1 &lt;merge-commit&gt; # 保留分支1的更改

git revert -m 2 &lt;merge-commit&gt; # 保留分支2的更改

===== 场景8:用 reflog 恢复误删的提交 =====

git reflog

efgh HEAD@{0}: commit: restore to v2

...

dcba HEAD@{5}: commit: v4(被 reset 删掉的提交)

git checkout dcba

以 detached HEAD 状态查看旧提交

或 git branch recovery-branch dcba 恢复到新分支

echo "回退撤销操作完成!"

常见问题

Q1: git reset --hard 误用了,已经提交的代码还能恢复吗?

可以!使用 git reflog 查看所有 HEAD 移动记录,找到被删除的提交哈希,然后 git checkout <commit-hash> 或创建新分支 git branch recovery <commit-hash> 恢复。reflog 默认保留约 90 天,所以误操作后应尽快恢复。

Q2: reset 和 revert 哪个更适合团队分支?

团队协作中几乎永远不要用 reset,因为它会重写提交历史,导致其他成员仓库不一致。revert 是更安全的选择,它创建一个新的"撤销"提交来反向操作,保留完整历史,不影响其他协作者。如果需要回退一个合并提交,使用 git revert -m 1 <commit> 指定保留哪个分支的更改。

Q3: 如何只撤销暂存区(已经 add)但保留工作区修改?

使用 git reset HEAD <文件>(或 git reset --mixed HEAD <文件>)可以将指定文件从暂存区移除,工作区修改保留。如果想取消所有暂存,用 git reset HEAD(无参数)。

Q4: checkout 和 restore 有什么区别?

在 Git 2.23 引入了更语义化的 git restore 来替代部分 git checkout 的功能:

  • <code>git restore &lt;文件&gt;</code> = <code>git checkout -- &lt;文件&gt;</code>(恢复工作区)<br>
  • <code>git restore --staged &lt;文件&gt;</code> = <code>git reset HEAD &lt;文件&gt;</code>(取消暂存)<br>
推荐使用 git restore,语义更清晰。

延伸阅读