Git revert - git reset --hard origin / <branch> </branch>

时间:2014-07-13 16:34:16

标签: git

我不小心输入了git reset --hard origin/<branch>(准确地说,我混淆了一些别名)。问题是我没有推动我的提交,现在他们已经丢失了。我能以某种方式回来吗?

2 个答案:

答案 0 :(得分:4)

在错误的git reflog之前,先向{1}}进行checkoutreset。 (也许先修复你的别名。)

答案 1 :(得分:2)

我看到你已经从中恢复了,但是,这是思考它的方法。您必须根据&#34; commit graph&#34;:一组提交(我用单个字母标记)来查看您的提交,其中每个提交都指向其父提交。带有一个分支并在其中合并的链看起来像这样:

         C <- D
       /        \
A <- B            G <- H <- I
       \        /
         E <- F

所有箭头指向后方(或者对于有角度的箭头指向后退/上下,我没有箭头可用,所以我只使用\/)。

分支,例如masterdevel,只是带有箭头的标签,指向图表中的某个提交。 (特殊标签HEAD通常只包含其他标签的名称,例如master,因此我将其写为HEAD=master。这会让您知道,如果有其他标签,哪一个是如果我们有颜色,我们可以将它变成鲜红色或绿色或其他颜色,但是对于文本,我们会选择HEAD=。)所以有了两个分支,我们可能会有这个:

         C <- D
       /        \
A <- B            G <- H <- I   <-- HEAD=master
       \        /
         E <- F                 <-- feature

这告诉我们,我们在分支master上,该分支master将提交标记为I(实际上是一些丑陋的SHA-1,如d1574b8... - 这就是我使用单个字母绘制图形的原因!),并且该分支feature将提交标记为F

git reset有什么作用 - 它有几个作业,但是用标签做什么来改变标签所指向的提交。由于您已经master,如果您git reset feature(我们暂时忽略--hard),您就会告诉git:&#34;删除从现在的任何地方标记master并使其指向与feature相同的提交,即提交F。&#34;这不会改变提交图本身,只需移动标签:

         C <- D
       /        \
A <- B            G <- H <- I
       \        /
         E <- F                 <-- feature, HEAD=master

通过&#34; reflog&#34;,提交I仍在那里(保留在存储库中)一段时间(默认为30到90天),因此您可以找到SHA- 1通过reflog提交I,直到那些reflog条目到期为止,并使用另一个git reset使你的标签指向它, 1

(&#34;远程分支&#34;标签origin/master就像您自己的本地分支标签一样,有一个很大的不同: 2 它会在您使用{时更新{1}}或git fetchgit pull获取新内容,而不是在本地执行操作。因此,它可以让您在提交图中找到提交,就像您自己的分支一样。&#39;为什么你可以将这些名称与origin一起使用:git reset只需要识别你希望当前分支标签指向的提交。)


reset命令还有一堆模式选项:reset--soft--mixed,还有一些更深奥的模式选项。这些会影响其其他作业。除了将分支标签从一个提交移动到另一个提交,--hard可以更新您的索引,还可以更新您的工作树。 git reset参数告诉它:&#34;不要更新任何一个!别管他们!&#34;在这种情况下,事物--soft完成的是移动标签。 3

默认值git reset告诉它:&#34;更新索引,但不要单独使用工作树。&#34;在这种情况下,--mixed移动标签,更新索引以匹配您移动到的提交。

使用git reset,您告诉它:&#34;更新索引,并使工作树匹配。&#34;在这种情况下,它可以擦除正在进行的工作,因为它使工作树匹配它与目标提交匹配的索引。

请注意,如果您说--hard - 即,您告诉git reset HEAD将当前分支从现在的任何地方移动到现在的任何位置 - 标签更改实际上根本没有变化。如果您在分支git reset上,则告诉git删除标签master,然后将其重新绘制到master指向的地方,然后再删除它。它最终指向它指向的位置。在这种特殊情况下,唯一真正的效果是您要求的任何索引和/或工作树更改。

您也可以将索引和/或工作树更改限制为特定文件。完全一般,您使用master 4 执行此操作。这意味着:&#34;将当前分支移至 git reset branch -- path ,并执行branch重置了给定的 --mixed 。&#34;如果 path branch,则分支不会移动,但 HEAD 的索引条目会匹配当前的提交。换句话说,您path编辑的任何新版本都是未完成的。因此git add告诉git:不要移动到任何地方,但要将索引中的git reset HEAD -- foo.txt恢复到当前提交,取消暂存foo.txt

如果您遗漏 foo.txt 部分,则默认为branch,这就是为什么HEAD是如何撤消git reset的原因1}}。工作树版本仍然存在,但索引条目已重新设置。 (更准确地说,是您命名的文件的索引条目,如果您命名为任何文件,或者是所有文件。)

使用git-add,它通过重置索引条目并使工作树与它们匹配来消除文件中的更改。并且它仍然默认使用--hard,这就是为什么HEAD(没有其他参数)摆脱所有未提交的更改(因此失去了你的工作,所以你真的意味着得到摆脱他们,我们希望......)。


1 实际上,您可以在不使用原始SHA-1的情况下执行此操作:git reset --hard。 Reflog名称适用于需要提交ID的任何地方。

2 还有一些较小的差异,例如,你不能让git reset HEAD@{1}命名为&#34;远程分支&#34;。如果你试试,你只需要一个&#34;分离的HEAD&#34;,它本质上是一个没有标签的本地分支。

3 这对于#s; squash commits&#34;非常有用,但是 - 因为那里HEAD - 不再是其他的了。在过去,您可以使用它来备份一个提交然后进行替换,但现在您可以使用git commit --amend更轻松地完成此操作。

4 实际上,在我有 --amend 的地方,你可以使用任何引用来解析为commit-ID 。这就是为什么脚注1中的reflog-name工作的原因。