git reset --hard HEAD〜1和git revert HEAD之间有何异同?

时间:2019-04-15 17:06:55

标签: git head revert

我正在努力解决这个问题。

据我所知,“ git reset --hard HEAD〜1”将删除最后一个提交,并且该提交不会在“ git log”中显示。

然后,“ git revert HEAD”将使我进入nano,在那里我可以编辑提交消息,并且还将还原保存为新提交,并保存在“ git log”中。

我对吗?

3 个答案:

答案 0 :(得分:2)

实际上,git revert将产生一个提交,该取消另一个给定提交的效果,并重播其变更集的否定版本。特别是 git revert 不会做 mercurial 会做的事情。

您可以将其看作是“维基百科”的取消:还原内容与其他内容一样被视为修改,并且可以注明日期。

git reset,但是,会将分支指针带回到给定位置。根据您指定的参数--soft--mixed(默认)或--hard,git只会分别修改分支指针,分支和索引的状态,或分支,索引和工作目录内容。因此,这是用来完全摆脱分支尖端的方法,但是命令可以在这种情况下采取行动。

请注意,即使您使用git reset --hard或其他方式取消引用提交,该提交也将保留在对象集合中,直到运行垃圾收集器为止,并且仅在其足够旧(通常为三个月)时才被丢弃。 / p>

因此请记住,如果您不小心这样做了,那么只要不等待太久,总有一种方法可以恢复提交。

答案 1 :(得分:1)

您是对的...。就工作树的外观而言,它们可能会给您相同的“最终结果”……但是该项目的最终历史却截然不同…………如果您问我,如果您刚刚发现不需要最后一次提交,则将其完全从历史记录中删除(DbSet<>.Add())。除非有主要理由不这样做。有人说,一旦发布,就不应撤回...我的看法是,任何经验丰富的git用户都知道如何使用--onto将内容重新编入基础,并指定对 skip 的修订,因此即使如果已发布,则应将其删除(让其他开发人员知道您的所作所为)....但这只是我的假设/意见。

答案 2 :(得分:1)

What's the difference between Git Revert, Checkout and Reset?上查看本来很好的(和重复的)问答,但是我们应该从更基本的内容开始。

为什么要使用版本控制?

版本控制系统的目的是为了永久保存所有所做的一切。好吧,除非不是这样:有时的目的是为了保存 all 时间中的 some 东西,为保存 some >一些时间,而有些事情则在很短的时间内。

Git保存的

方式是完整的快照,我们称之为 commits ,其中还包含有关提交的一些额外信息,我们称之为 metadata 。元数据包括提交人员的姓名和电子邮件地址,以便我们可以询问他们为什么为什么,以及一条日志消息,以便他们可以告诉我们为什么没有提交该信息我们不得不打扰他们。 Git中的元数据还包括先前或 parent 提交的概念。通过将父快照与此特定快照进行比较,Git可以告诉我们进行提交的人已更改

牢记这一点,我们可以看一下这三个Git动词(我也将投入git checkout):

git checkout是要在某个时候完成某件事

我们使用git checkout获得一个特定的提交。提交是某人有时所做的快照。大概快照对于某些目的是有好处的。无论我们的下一个目标是什么,我们都使用git checkout来获取快照,与当时的快照完全一样。

在Git中,由于使用带有{em>分支名称的git checkout的副作用,我们现在准备进行 new 工作。但是我们也可以将git checkout与原始提交哈希一起使用,在此之后,新的提交就变得很棘手了。 (它们仍然可能,但是Git称为这种分离式HEAD 模式,您可能不希望使用它,直到您对Git有了更多的了解。)

例如,git checkout master可以对master进行最新提交的原因是,每次我们提交 new 提交时在master上,Git自动更新我们的名称master,使其表示最新的此类提交。最新的提交会记住它的父级,该父级曾经是最新的。第二个单向提交记得父级,当单向提交也不存在时,它是最新的,依此类推。

这意味着名称 master实际上只是找到了 last 提交,从中我们找到了每个更早的提交:

... <-F <-G <-H   <--master

,每个大写字母代表一个提交哈希ID。我们说每个提交指向其父级,master 指向最新的提交。

git revert是要撤消错误的提交

鉴于每个提交都记录了其父对象,因此Git可以告诉我们进行该提交的人做了什么更改,我们总是可以让Git undo 别人的更改(甚至我们自己的)。我们选择一个提交,将其视为更改(这是当我们使用git log -pgit show时Git向我们显示的提交),发现,嘿,该更改是错误。该更改应撤回或“还原”。 1


1 动词 revert 在这里实际上是一个不好的选择。 most common English language definition几乎总是跟着辅助词 to ,如 revert to 一样,它意味着返回到先前的状态。但是,放弃某些更改并不一定会使我们回到旧状态!如果我们撤消最新更改,我们只会返回到以前的状态。

其他版本控制系统使用动词 backout ,效果更好。无论如何,当我们使用该动词时,Git都会进行一次 new 提交,并保存一个新快照,该快照与我们之前的检出一样,只是它撤消了某人的更改。好吧,就是说,除非存在合并冲突,否则Git会进行此提交,但是在这里我们将忽略这种可能性。


git reset……很混乱,但是我们可以用它扔掉提交

Git的 reset 动词非常复杂。在一种特定形式中,它最多可以完成三件事。使用其他形式,它可以执行其他操作。您特别询问的人git reset --hard HEAD~1告诉Git:

  1. 使当前分支为 name ,无论它是什么,都指向当前提交的父级。
  2. 删除当前的 index -在这里我们没有描述,但是 index 临时区域,甚至是 cache < / em>实际上只是Git中同一事物的三个名称-并从步骤1中选择的提交中填写。
  3. 在重置索引之前,删除与索引一起的所有工作树文件,然后将其替换为从步骤1中选择的提交中提取并在步骤2中复制到索引中的副本。 / li>

所以,如果我们有:

... <-F <-G <-H   <--master

我们已将名称 master更改为指向G,将提交H推开了:

            H
           /
... <-F <-G   <-- master

哈希为H的提交现在有效地丢失,好像从未进行过。它仍然在存储库中 找到变得越来越困难。随着时间的流逝,如果我们不采取其他任何措施来保存它,那么提交H将会消失。

记住我们的提交目的

我们想要提交,以便它们保存所有时间所做的所有事情。但是有时候,我们所做的(例如,也许进行提交H)是一个错误:

...--F--G--H--I--J--K--L   <-- master

如果我们前段时间制作了H,并且都像这样嵌入,那么很难删除,因为每个提交都被完全冻结,因此要删除 H,我们必须复制 I到以I'为父节点的新提交G,然后将J复制到新提交I作为其父级,依此类推:

          H--I--J--K
         /
...--F--G--I'-J'-K'  <-- master

在这里,还原 H更加容易,添加新的提交可以撤消我们在H中所做的更改。从IK的提交保持不变-可能略有破损,但这就是他们一直以来的样子-现在我们有了一个新的提交L,以撤消在{{1 }}:

H

但是如果...--F--G--H--I--J--K--L <-- master 是最近的版本,我们可以完全使用H删除它。我们会忘记我们曾经犯过的错误。无需告诉其他任何人。