原文:The Ultimate Guide to Git Reset and Git Revert

欢迎阅读 git resetgit revert 命令终极指南。本教程将教你在使用 Git 时修复常见错误和撤消错误提交所需的一切。

理解一个 Git 项目的三个部分

一个 Git 项目有以下三个主要部分:

  • Git 目录
  • 工作目录(或工作树)
  • 暂存区

Git 目录(位于 你的项目路径/.git/ 中)是 Git 存储准确跟踪项目所需的一切的地方。 这包括元数据和包含项目文件压缩版本的对象数据库。

工作目录是用户对项目进行本地更改的地方。工作目录从 Git 目录的对象数据库中提取项目文件并将它们放在用户的本地机器上。

注意:目录也被称为仓库(repository)。用户本地机器上的仓库是“本地仓库”,而 git 服务器上的仓库是“远程仓库”。

暂存区是一个文件(也叫“索引”或“缓存”),用于存储有关下一次提交内容的信息。提交是你告诉 Git 保存这些阶段性更改。Git 按原样获取文件的快照,并将该快照永久存储在 Git 目录中。

通过三个部分,文件可以在任何给定时间处于三种主要状态:已修改、已提交或已暂存。每当你在工作目录中对文件进行更改时,你都会修改该文件。接下来,当你将其移动到暂存区时,它就会被暂存。最后,它在一次提交后被提交

Git Reset

git reset 命令允许你将当前头部重置为指定状态。你可以重置特定文件以及整个分支的状态。如果你尚未将提交推送到 GitHub 或其他远程仓库,这将非常有用。

重置一个文件或一组文件

以下命令可让你选择内容块,并还原或取消暂存。

git reset (--patch | -p) [tree-ish] [--] [paths]

取消暂存文件

如果你使用 git add  将文件移动到暂存区,但不再希望它成为提交的一部分,则可以使用 git reset 取消暂存该文件:

git reset HEAD FILE-TO-UNSTAGE

你所做的更改仍将保留在文件中,此命令只是从暂存区中删除该文件。

将分支重置为先前的提交

以下命令将你当前分支的 HEAD 重置为给定的 COMMIT 并更新索引。它会回滚你的分支的状态,然后你所做的所有提交都会覆盖重置点之后的任何内容。如果省略 MODE,则默认为 --mixed

git reset MODE COMMIT

MODE 的选项是:

  • --soft:不重置索引文件或工作树,但重置 HEAD 为 commit。将所有文件更改为“要提交的更改”。
  • --mixed:重置索引,但不重置工作树,并报告尚未更新的内容。
  • --hard:重置索引和工作树。commit 之后对工作树中跟踪文件的任何更改都将被丢弃。
  • --merge:重置索引,并更新工作树中 commit 和 HEAD 之间不同的文件,但保留索引和工作树之间不同的文件。
  • --keep:重置索引条目,并更新工作树中 commit 和 HEAD 之间不同的文件。如果 commit 和 HEAD 之间不同的文件有本地更改,则中止重置。

关于硬重置的重要说明

--hard 选项与 git reset 一起使用时要非常小心,因为它会重置你的提交、暂存区和你的工作目录。如果未正确使用此选项,则最终可能会丢失所编写的代码。

Git Revert

git revertgit reset 命令都撤消以前的提交。但是,如果你已经将提交推送到远程仓库,则建议你不要使用 git reset,因为它会重写提交的历史记录。这会使与其他开发人员一起处理仓库并维护一致的提交历史变得非常困难。

使用 git revert 会更好。它通过创建一个全新的提交来撤消先前提交所做的更改,所有这些都不会改变提交的历史记录。

还原一个提交或一组提交

以下命令允许你从先前的一个或多个提交中恢复更改,并创建一个新的提交。

git revert [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>…
git revert --continue
git revert --quit
git revert --abort

Common 选项:

  -e
  --edit
  • 这是默认选项,不需要显式设置。它会打开你系统的默认文本编辑器,并让你在提交还原之前编辑新的提交消息。
  • 此选项与 -e 的作用相反,并且 git revert 不会打开文本编辑器。
  • 此选项可防止 git revert 撤消先前的提交并创建新的提交。-n 不是创建新提交,而是撤消先前提交的更改,并将它们添加到暂存索引和工作目录中。
  --no-edit
-n
-no-commit

示例

让我们想象一下以下情况:1)你正在处理一个文件,添加并提交了更改。2)然后你做一些其他的事情,并进行更多的提交。3)现在你意识到,在三四次提交之前,你做了一些你想撤销的事情——你怎么能做到这一点?

你可能会想,只需使用 git reset,但这将删除你想要更改的提交之后的所有提交——git revert 来救援!让我们来看看这个例子:

mkdir learn_revert # Create a folder called `learn_revert`
cd learn_revert # `cd` into the folder `learn_revert`
git init # Initialize a git repository

touch first.txt # Create a file called `first.txt`
echo Start >> first.txt # Add the text "Start" to `first.txt`

git add . # Add the `first.txt` file
git commit -m "adding first" # Commit with the message "Adding first.txt"

echo WRONG > wrong.txt # Add the text "WRONG" to `wrong.txt`
git add . # Add the `wrong.txt` file
git commit -m "adding WRONG to wrong.txt" # Commit with the message "Adding WRONG to wrong.txt"

echo More >> first.txt # Add the text "More" to `first.txt`
git add . # Add the `first.txt` file
git commit -m "adding More to first.txt" # Commit with the message "Adding More to first.txt"

echo Even More >> first.txt # Add the text "Even More" to `first.txt`
git add . # Add the `first.txt` file
git commit -m "adding Even More to First.txt" # Commit with the message "Adding More to first.txt"

# OH NO! We want to undo the commit with the text "WRONG" - let's revert! Since this commit was 2 from where we are not we can use git revert HEAD~2 (or we can use git log and find the SHA of that commit)

git revert HEAD~2 # this will put us in a text editor where we can modify the commit message.

ls # wrong.txt is not there any more!
git log --oneline # note that the commit history hasn't been altered, we've just added a new commit reflecting the removal of the `wrong.txt`

掌握了这些,你离获得 Git 黑带又近了一步。