在 Git 中巧妙修正错误

Avatar of Tobias Günther
Tobias Günther

DigitalOcean 为您旅途的每个阶段提供云产品。 立即开始使用 200 美元的免费额度!

软件开发的世界提供了无限种出错的方式:删除错误的东西、代码陷入死胡同、提交信息中充斥着拼写错误,这些仅仅是其中一小部分。
​​
​​幸运的是,当我们使用版本控制时,Git 为我们提供了可靠的安全网。当然,你我并不需要安全网,因为我们从不犯错,对吧?好吧,好吧,为了其他人的利益,让我们来了解一些 Git 中的“撤销”工具,它们可以帮助我们避免自误。
​​
​​
​​
​​

修正最后一次提交

​​
​​提交错误很容易发生。典型的例子是:在提交信息中出现拼写错误。另一个例子是:忘记将更改添加到暂存区。在很多情况下,我们会在按下回车键后立即意识到自己的错误,这很自然。
​​
​​幸运的是,Git 使修正最后一次提交变得非常容易。假设我们刚刚对以下命令按下了回车键

​​

git commit -m "Massage full of typohs"

​​
​​并且(就好像这个拼写错误还不够糟糕一样)假设我们还忘记将另一个已更改的文件添加到暂存区。我们可以使用以下两条命令来修正这两个错误
​​

git add forgotten-changes.js
​​git commit --amend -m "A sensible message"

​​
​​神奇之处在于--amend​标志:当在提交中使用它时,Git 会修正最后一次提交,并包括任何暂存的更改和新的信息。
​​
​​不过,要提醒一点:只对尚未推送到远程存储库的提交使用--amend​。原因是 Git 会用修正后的版本替换原始的错误提交。之后,看起来原始提交从未发生过。没错,这对于隐藏错误很有用,但前提是我们还没有在远程服务器上发布这个错误。
​​​​
​​

撤销本地更改

​​
​​每个人都经历过这样的日子:整个上午都在不停地敲代码,最后才承认自己过去的几个小时浪费了时间。必须重新开始,撤销大部分(或全部)的工作。
​​
​​但这正是我们使用 Git 的原因之一——能够尝试各种东西,而无需担心会破坏任何东西。
​​
​​让我们以一个示例情况为例
​​

git status
​​  modified: about.html
​​  deleted:  imprint.html
​​  modified: index.html

​​
​​现在,假设这是上面提到的那些浪费时间的代码编写日之一。我们应该避免修改about.html,并且不应该删除imprint.html。我们现在想要丢弃这些文件中当前的更改,同时保留在index.html中完成的出色工作。​​git checkout​命令可以帮助我们解决这个问题。相反,我们必须更明确地指定要签出的文件,如下所示

​​

git checkout HEAD about.html imprint.html

​​这条命令将about.html和imprint.html恢复到它们最后一次提交的状态。Phew,我们逃过一劫!
​​
​​我们可以更进一步,丢弃更改文件中特定行的内容,而不是丢弃整个文件!我承认,在命令行中进行操作相当复杂,但使用像Tower这样的桌面 Git 客户端是一个很好的选择

​​
​​对于那些真正糟糕的日子,我们可能需要使用强大的武器,即
​​
​​

git reset --hard HEAD

​​
​​虽然我们只用checkout​恢复了特定文件,但这项命令会重置我们的整个工作副本。换句话说,reset​会将整个项目恢复到最后一次提交的状态。​​与--amend​类似,在使用checkout​和reset​时需要注意的一点是:使用这些命令丢弃本地更改是不可逆转的!这些更改从未提交到存储库,因此它们无法恢复也是合乎逻辑的。最好确保你确实想要丢弃这些更改,因为无法恢复!
​​
​​

撤销和回退较旧的提交

​​
​​在很多情况下,我们直到很久以后,在提交到存储库很久以后才意识到错误。

​​我们如何才能删除那个错误的提交?答案是我们不应该删除... 至少在大多数情况下不应该删除。即使是在“撤销”操作中,Git 通常也不会真正删除数据。它会通过添加新数据来进行修正。让我们来看看使用我们的“错误提交”示例如何实现这一点
​​
​​

git revert 2b504bee

​​
​​通过对那个错误的提交使用git revert​,我们并没有删除任何东西。恰恰相反

​​Git 会自动创建一个新的提交,其中包含撤销“错误”提交的效果的更改。因此,如果我们最初有三个提交,并且试图修正中间那个提交,现在我们总共有了四个提交,新添加的提交会修正我们用revert​目标指定的提交。
​​​​
​​

恢复项目的先前版本

​​
​​另一种用例是我们想要恢复项目的先前版本。我们可能并不想仅仅撤销或回退提交历史记录中的特定修订,而是真正想倒流时间,回到特定修订。
​​
​​在以下示例场景中,我们将声明“C2”之后的所有提交都是不必要的。我们想要回到“C2”提交的状态,并将此过程中之后的所有提交都忘掉

​​必要的命令(至少部分)你已经通过我们已经讨论的内容了解了
​​
​​

git reset --hard 2b504bee

​​
​​这会告诉git reset​我们想要返回的提交的 SHA-1 哈希值。提交 C3 和 C4 随后会从项目的提交历史记录中消失。
​​
​​如果你使用的是 Git 客户端,比如 Tower,那么git revert​和git reset​都可以在提交项的上下文菜单中找到

​​

​​删除提交、恢复已删除的分支、处理冲突等等等

​​
​​当然,在软件项目中还有很多其他方法会导致错误。但幸运的是,Git 还提供了更多工具来修正混乱。
​​
​​如果你想了解更多关于我们在本文中讨论的场景或其他主题的信息,比如如何在分支之间移动提交、删除旧提交、恢复已删除的分支或优雅地处理合并冲突,请查看我和 Tower 团队的其他成员创建的“Git 急救手册”项目。 这是一份完全免费的指南,包含 17 个视频和一个方便的备忘单,你可以下载并将其放在你的机器旁。

​​同时,祝你撤销愉快!