如何安全撤销 Git 错误:`Revert`、`Reset` 和 `Checkout` 命令详解

自信地处理 Git 错误!本指南介绍了 `git revert`、`git reset` 和 `git checkout`,以便您安全地撤销提交、恢复文件以及管理您的仓库历史记录。了解何时以及如何使用每个命令来纠正错误而不会丢失宝贵的工作,使其成为任何 Git 用户的必备阅读材料。

如何安全地撤销 Git 错误:详解 Revert、Reset 和 Checkout

Git 错误通常感觉比实际更糟糕。你可能提交了错误的文件、暂存了太多内容,或者将错误的更改推送到了共享分支。安全的修复方法取决于一个问题:更改是否已经共享?

本指南解释了何时使用 git revertgit resetgit checkout,并提供了可以仔细复制的示例。简单来说:对已共享的提交使用 git revert,对本地清理使用 git reset,仅在切换分支或恢复旧文件状态时使用 git checkout

首先,检查你要撤销的内容

在运行任何撤销命令之前,先查看当前状态:

git status
git log --oneline --decorate -5

git status 告诉你是否有未暂存、已暂存或未跟踪的工作。git log 显示最近的提交以及分支指向的位置。

如果你有不想丢失的本地工作,请先创建一个快速的安全分支:

git branch backup-before-undo

如果你选择了错误的命令,这个分支可以让你轻松返回。

对已推送的提交使用 git revert

git revert 会创建一个新提交,该提交应用了先前提交的相反更改。它不会删除历史记录,因此对于共享分支(如 maindevelop 或任何其他人可能已拉取的分支)来说是最安全的选择。

假设你的历史记录如下所示:

A -- B -- C -- D  main

提交 C 引入了一个错误,但 D 是好的且必须保留。找到提交哈希:

git log --oneline

然后仅还原该提交:

git revert abcdef1

Git 会打开编辑器让你输入还原提交的消息。保存后,历史记录如下所示:

A -- B -- C -- D -- E  main

提交 E 撤销了 C 的更改。每个人都可以正常拉取这个新提交。

还原合并提交

合并提交需要一个额外的标志,因为 Git 必须知道哪个父提交是主线:

git revert -m 1 <merge-commit-hash>

对于合并到 main 的正常合并,-m 1 通常意味着“保留第一个父提交”,即你合并到的分支。不要在这里猜测。首先运行以下命令并检查父提交:

git show --summary <merge-commit-hash>

如果你不确定要保留哪个父提交,请询问团队成员或在临时分支上测试还原。

对本地提交使用 git reset

git reset 会移动当前分支指针。根据模式的不同,它还可以更改暂存区和工作文件。主要用于尚未推送的提交。

取消暂存文件

如果你暂存了错误的文件,可以在不更改文件内容的情况下取消暂存:

git restore --staged unwanted_file.txt

较旧的 Git 示例通常使用以下等效命令:

git reset HEAD unwanted_file.txt

两者都将文件从暂存区中移除。你的编辑保留在工作目录中。

撤销最后一次提交但保留更改已暂存

当提交消息错误或你想在重新提交前再添加一个文件时,使用 --soft

git reset --soft HEAD~1

你的分支向后移动一次提交,但该提交的更改仍处于暂存状态。

撤销最后一次提交并保留更改未暂存

当你希望在再次提交之前重新处理文件时,使用默认的混合重置:

git reset HEAD~1

这会将分支向后移动一次提交,并将更改保留在工作目录中。

丢弃本地提交和文件更改

--hard 会重置分支、暂存区和工作目录中的跟踪文件:

git reset --hard HEAD~1

仅在你确定不需要丢弃的更改时使用此选项。它不会删除未跟踪的文件,但会丢弃跟踪文件的编辑而不会再次询问。

谨慎使用 git checkout

在较旧的 Git 工作流中,git checkout 有两个常见任务:切换分支和恢复文件。较新的 Git 版本将这些任务分成了更清晰的命令:git switch 用于分支,git restore 用于文件。

切换分支:

git switch main

旧版等效命令:

git checkout main

丢弃一个跟踪文件中的未提交更改:

git restore my_file.txt

旧版等效命令:

git checkout -- my_file.txt

该文件恢复对于所选文件中未提交的编辑是破坏性的。如果你以后可能需要这些编辑,请先 stash 它们:

git stash push -m "save work before restore"

如果操作过头,使用 git reflog

如果你运行了 git reset --hard 或错误地移动了分支,git reflog 可能仍然显示 HEAD 之前指向的位置:

git reflog

你可能会看到像 HEAD@{2} 这样的早期条目或重置之前的提交哈希。你可以从中创建一个恢复分支:

git branch recovery <commit-hash>

Reflog 是本地克隆的,不是备份系统,但它通常能帮你从最近的错误中恢复。

应该选择哪个命令?

当错误提交已推送或其他人可能基于它工作时,使用 git revert

当最后一次本地提交需要重做但更改仍然正确时,使用 git reset --soft

当你希望将最后一次本地提交恢复为未暂存的文件更改时,使用 git reset

仅当本地跟踪的更改可以删除时,使用 git reset --hard

当你想丢弃特定文件中的未提交更改时,使用 git restoregit checkout -- <file>

最安全的习惯是检查 git status,在风险较高时创建一个临时备份分支,并避免重写共享历史。如果提交已到达共享远程仓库,git revert 通常是最干净的修复方法。