撤销 Git 中的更改:Reset、Restore、Revert 详解

理解 git restore、reset 和 revert,以便取消暂存文件、丢弃本地编辑、撤销提交,并避免重写共享历史。

撤销 Git 中的更改:Reset、Restore、Revert 详解

在 Git 中撤销更改是安全的,只要你知道你在修改哪一层:工作目录、暂存区还是提交历史。常用的命令有 git restoregit resetgit revert,它们解决不同的问题。

一个大原则很简单:对文件使用 restore,对本地历史更改使用 reset,对撤销其他人可能已经拥有的提交使用 revert

理解核心概念

请分清这些区域:

  • 工作目录:你编辑的文件。
  • 暂存区,也称为索引:为下一次提交选中的更改。
  • 提交历史:已经记录的提交。
  • HEAD:你的分支当前指向的提交。

在撤销任何操作之前运行 git status。它会告诉你更改是未暂存、已暂存还是已提交。

git restore:用于丢弃工作目录和暂存区中的更改

当你想要更改工作目录或暂存区中的文件而不移动分支历史时,使用 git restore

取消暂存文件

如果你错误地暂存了一个文件,使用 --staged 取消暂存:

git restore --staged <file>

要取消暂存所有内容:

git restore --staged .

你的文件编辑仍保留在工作目录中。它们只是从下一次提交中移除。

丢弃工作目录中的更改

要丢弃一个文件中未暂存的编辑:

git restore <file>

这会使工作目录副本与索引匹配。如果文件未暂存,这通常意味着它回到 HEAD。先查看 git diff,因为这会丢弃本地编辑。

要丢弃一个文件的已暂存和未暂存更改,并从 HEAD 恢复:

git restore --source=HEAD --staged --worktree <file>

从特定提交恢复文件

你也可以从较旧的提交中恢复一个文件:

git restore --source=<commit> -- path/to/file

这会更改工作目录中的文件。如果旧版本是你想要的,就提交它。

git reset:重写历史

当你想要移动当前分支指针时,使用 git reset。根据模式的不同,它还可以更改暂存区和工作目录。

理解模式(--soft--mixed--hard

三种常见模式是:

git reset --soft HEAD^

HEAD 向后移动一个提交,并保留被撤销提交的更改处于暂存状态。

git reset --mixed HEAD^

HEAD 向后移动一个提交,并保留被撤销提交的更改处于未暂存状态。--mixed 是默认模式,所以 git reset HEAD^ 执行相同的操作。

git reset --hard HEAD^

HEAD 向后移动一个提交,并从暂存区和工作目录中丢弃相应的更改。这是破坏性的。不要随意运行。

有用的 reset 模式:

git reset --soft HEAD^      # 重做最后一个本地提交,保持更改暂存
git reset HEAD^             # 撤销最后一个本地提交,保持更改未暂存
git reset                   # 取消所有已暂存的更改
git reset --hard origin/main # 丢弃本地更改并与 origin/main 匹配

重置旧提交

要将分支向后移动两个提交,同时保留工作目录中的更改:

git reset --mixed HEAD~2

只重置本地的提交,或者你的团队同意重写的提交。如果提交已经在共享分支上,优先使用 git revert

git revert:创建新提交以撤销更改

git revert 创建一个新提交,该提交应用早期提交的逆操作。它不会删除或移动原始提交,因此对于共享分支是安全的。

撤销一个提交:

git revert <commit-hash>

撤销一个范围:

git revert HEAD~3..HEAD

如果出现冲突,解决冲突,暂存文件,然后继续:

git add <fixed-files>
git revert --continue

撤销合并提交需要额外注意,因为 Git 必须知道哪个父提交应被视为主线:

git revert -m 1 <merge-commit>

只有在你理解合并引入了什么时才这样做。对于生产分支,在撤销合并之前请求审查。

选择正确的命令

使用这个快速指南:

  • 取消暂存文件:git restore --staged <file>
  • 丢弃文件中未暂存的编辑:git restore <file>
  • 撤销最后一个本地提交并保持更改暂存:git reset --soft HEAD^
  • 撤销最后一个本地提交并保持更改未暂存:git reset HEAD^
  • 破坏性地丢弃本地更改和提交:git reset --hard <commit>
  • 安全地撤销已推送的提交:git revert <commit-hash>

实用要点

在撤销任何操作之前,运行 git status 并决定你要更改什么。对文件级清理使用 restore,对本地未推送的提交使用 reset,对共享历史使用 revert。当命令包含 --hard 时,暂停并先检查 git diff