软件开发,无论经验多丰富,都难免出错。但优秀程序员与普通程序员的区别在于,他们知道如何撤销错误!
如果你使用 Git 作为版本控制系统,那么你已经拥有了一套强大的“撤销工具”。本文将向你展示五种强大的 Git 撤销错误的方法!
git restore
命令完成,该命令会将文件重置为其最后一次提交的状态。为了更精细的控制,可以使用 -p
标志在补丁级别丢弃更改。git log
命令可用于将特定文件恢复到特定版本。用户可以识别文件损坏的“错误提交”,然后使用 git checkout
命令将文件恢复到错误提交之前的版本。Reflog
工具可用于恢复丢失的版本或已删除的分支。Reflog
记录本地存储库中所有 HEAD 指针的移动,允许用户返回到以前的状态并恢复丢失的数据。git cherry-pick
命令将提交移动到不同的分支。如果提交到错误的分支,用户可以检出正确的分支,将提交移动过去,然后使用 git reset
从原始分支中删除不需要的提交。编码过程通常很混乱。有时,感觉像是两步前进,一步后退。换句话说:你编写的一些代码很棒……但有些则不然。这就是 Git 可以帮助你的地方:它允许你保留好的部分,并丢弃不再需要的更改。
让我们来看一个包含一些“本地”更改(即尚未提交的更改)的示例场景。
注意:为了更好的概述和更清晰的可视化,我在一些屏幕截图中使用了 Tower Git 桌面客户端。你不需要 Tower 就可以学习本教程。
让我们先解决 general.css
中的问题。我们所做的更改完全朝着错误的方向发展。让我们撤销所有更改,并重新创建该文件的最后一次提交状态:
$ git restore css/general.css
请注意,或者,我也可以使用 git checkout
命令来达到相同的结果。但是因为 git checkout
有很多不同的用途和含义,所以我更倾向于使用稍微更新一些的 git restore
命令(它只专注于这些类型的任务)。
我们在 index.html
中的第二个问题有点棘手。我们在这个文件中做的一些更改实际上是很好的,而只有一部分需要撤销。
同样,git restore
命令可以解决问题——但这次要使用 -p
标志,因为我们要深入到“补丁”级别:
$ git restore css/general.css
然后,Git 会引导你,并询问你——对于该文件中的每一块更改——你是否要丢弃它。
你会注意到,我对第一块更改输入了“n”(为了保留它),对第二块更改输入了“y”(为了丢弃它)。该过程完成后,你会看到只有第一块有价值的更改保留了下来——就像我们想要的那样!
有时,你可能想要将特定文件恢复到特定版本。例如,你知道 index.html
在之前的某个时间点工作正常,但现在不行了。这时你想要倒退时间,但只针对这个特定文件,而不是整个项目!
我们首先需要找出我们想要恢复的哪个确切版本。使用正确的参数集,你可以让 git log
命令显示你单个文件的历史记录:
$ git restore -p index.html
这只会显示 index.html
被更改的提交,这对于查找导致问题出现的“坏苹果”版本非常有用。
如果你需要更多信息,并想要查看这些提交的内容,你可以让 Git 使用 -p
标志显示这些提交中的实际更改:
$ git log -- index.html
一旦我们找到了导致我们可爱的小文件损坏的错误提交,我们就可以继续修复错误了。我们将通过恢复错误提交之前版本的该文件来做到这一点!这很重要:我们不想恢复引入错误的提交中的文件,而是恢复最后一个良好状态——该提交之前的那个提交!
$ git log -p -- index.html
将 ~1
附加到错误提交的哈希值将指示 Git 执行以下操作:转到引用的提交之前的一个版本。
执行该命令后,你会发现 index.html
在你的本地工作副本中被修改了:Git 为我们恢复了该文件的最后一个良好版本!
Git 急救包中的另一个强大的撤销工具是“Reflog”。你可以把它想象成一个日志,Git 在其中记录本地存储库中发生的所有 HEAD 指针移动——例如提交、检出、合并和变基、cherry-pick 和重置。所有更重要的操作都会在这里被很好地记录下来!
当然,这样的日志非常适合那些事情进展不顺利的情况。因此,让我们先制造一个小灾难——然后我们可以用 Reflog 来修复它。
假设你确信你最近的几次提交都不好:你想摆脱它们,因此使用了 git reset
来返回到之前的版本。结果,“错误”提交从你的提交历史中消失了——正如你想要的那样。
但正如生活有时那样,你注意到这是一个坏主意:最终,这些提交并没有那么糟糕!但坏消息是,你刚刚将它们从你的存储库的提交历史中删除了!?
这是 Git 的 Reflog 工具的经典案例!让我们看看它如何拯救你:
$ git restore css/general.css
让我们逐一分解:
git reflog
就足够了。为了恢复此先前状态,我们可以再次使用 git reset
,或者简单地创建一个新分支:
$ git restore -p index.html
正如我们可以高兴地验证的那样,我们的新分支包含了我们认为通过意外的 git reset
故障而丢失的提交!
Reflog 也可在其他情况下派上用场。例如,当你无意中删除了一个你真的不应该删除的分支时。让我们来看一下我们的示例场景:
$ git log -- index.html
让我们假设我们的客户/团队负责人/项目经理告诉我们,我们一直在开发的漂亮的分析功能不再需要了。我们井井有条,当然会删除相应的 feature/analytics
分支!
上面你可以看到,在我们的示例场景中,我们当前检出了该分支:feature/analytics
是我们当前的 HEAD 分支。为了能够删除它,我们必须首先切换到另一个分支:
$ git restore css/general.css
Git 告诉我们我们即将做一些非常严重的事情:由于 feature/analytics
包含在其他地方不存在的唯一提交,因此删除它将破坏一些(可能是有价值的)数据。好吧……既然不再需要该功能,我们可以继续:
$ git restore -p index.html
你可能已经预料到接下来会发生什么:我们的客户/团队负责人/项目经理高兴地告诉我们,该功能又回来了!? 他们毕竟想要继续进行!?
同样,我们面临一个糟糕的情况,我们可能丢失了宝贵的数据!因此,让我们看看 Reflog 是否可以再次拯救我们:
$ git log -- index.html
如果你仔细观察,好消息就会显而易见。在我们(灾难性地)能够删除我们的分支之前,我们必须执行 git checkout
以切换到其他分支(因为 Git 不允许你删除当前分支)。当然,此检出也记录在 Reflog 中。为了恢复我们已删除的分支,我们现在可以简单地将之前的状态作为新分支的起点:
$ git log -p -- index.html
瞧:我们的分支起死回生了!???
如果你碰巧使用的是 Tower 等桌面 GUI,撤消此类错误通常就像按下 CMD Z 一样简单。
最后,让我们再来看一个“哦,不!”部门的经典案例:在错误的分支上提交。
今天,许多团队都制定了一条规则,禁止直接提交到长期分支,如“main”、“master”或“develop”。通常,新的提交应该只通过合并/变基到达这些分支。然而,我们有时会忘记并直接提交……
让我们以以下场景为例。
我们应该在 feature/newsletter
上提交,但无意中在 master
分支上触发了提交。让我们一步一步地看看解决方案。
首先,我们必须确保这次我们在正确的分支上,所以我们正在检出 feature/newsletter
:
$ git checkout <bad-commit-hash>~1 -- index.html
现在我们可以使用 cherry-pick
命令安全地将该提交移动过去:
$ git reflog
我们可以查看 feature/newsletter
,将会看到该提交现在也存在于这里。
到目前为止,一切顺利。但是 cherry-pick
没有从 master
分支(它永远不应该在那里)删除提交。因此,我们也必须在那里清理我们的烂摊子:
$ git restore css/general.css
我们切换回 master
,然后使用 git reset
从历史记录中删除(这里)不需要的提交。
最后,一切又恢复正常了——所以你现在可以开始你的快乐舞蹈了!???
我以前说过,而且不幸的是我们都知道这是真的:我们无法避免错误!无论我们多么优秀的程序员,我们都会不时地搞砸。因此,问题不在于我们是否犯错,而在于我们如何有效地处理它们并解决问题?
如果你想了解更多关于 Git 撤销工具的信息,我强烈推荐“Git 急救包”。这是一个(免费的)简短视频合集,向你展示如何在 Git 中清理和撤消错误。
祝你开发顺利,勇于尝试,当然也要善于修复!
git reset
和 git revert
有什么区别?git reset
和 git revert
是两个帮助你撤消 Git 存储库中更改的命令,但它们的工作方式不同。git reset
将你的 HEAD 指针移动到特定的提交。这意味着它实际上“忘记”了你在重置到的提交之后的所有提交。这是一个破坏性操作,应该谨慎使用。另一方面,git revert
创建一个新的提交来撤消特定提交中所做的更改。这是一个安全的操作,因为它不会更改现有历史记录。
git add
操作?如果你已经使用 git add
暂存了更改,并且想要撤消此操作,可以使用 git reset
命令。例如,如果你想要取消暂存特定文件,可以使用命令 git reset <file></file>
。如果你想要取消暂存所有更改,可以使用 git reset
而不指定文件。
git commit
吗?是的,你可以使用 git reset
或 git revert
命令撤消 git commit
。git reset
将你的 HEAD 指针移回到你想要撤消的提交之前的提交,有效地擦除不需要的提交。另一方面,git revert
将创建一个新的提交来撤消不需要的提交中所做的更改。
如果你已经对特定文件进行了更改,并且想要撤消这些更改,可以使用 git checkout
命令。例如,git checkout -- <file></file>
将丢弃指定文件的本地工作目录中的更改。
git stash
是什么?git stash
是一个允许你临时保存你不想立即提交的更改的命令。如果你需要切换到不同的分支,但不想提交当前更改,这将非常有用。你可以稍后使用 git stash apply
应用暂存的更改。
你可以使用 git log
命令查看你的 Git 历史记录。这将向你显示存储库中所有提交的列表,以及它们的提交消息。
git push
吗?是的,你可以撤消 git push
,但这比撤消本地更改要复杂一些。你需要使用带有 -f
或 --force
选项的 git push
命令来用你的本地存储库覆盖远程存储库。要小心使用此命令,因为它可能会对正在处理同一存储库的其他人员造成问题。
如果你想要撤消多个提交,可以使用 git reset
命令以及 HEAD~<number></number>
语法。例如,git reset HEAD~3
将你的 HEAD 指针移回到三个提交之前。
软重置将你的 HEAD 指针移动到特定的提交,但不会更改你的工作目录和暂存区。这意味着你仍然会看到来自“已忘记”提交的更改作为未提交的更改。另一方面,硬重置将丢弃工作目录和暂存区中的所有更改,有效地将你的存储库恢复到指定提交时的状态。
是的,硬重置后可以恢复提交,但这并不简单。Git 会在 reflog 中保留所有 ref 更新(例如移动 HEAD 指针)的日志。你可以使用 git reflog
命令找到你想要恢复的提交,然后使用 git branch
在该提交处创建一个新分支。
以上是用git撤消错误的5种方法的详细内容。更多信息请关注PHP中文网其他相关文章!