是否会对新分支上的旧提交进行硬重置也会重置主设备?

时间:2016-07-13 14:36:02

标签: git git-branch git-reset

我想看看之前提交的设计是什么样的,所以我想签出一个新的分支,然后恢复/硬重置为旧的提交。

我很擅长提交,并且不想通过随机试验来破坏任何内容,因此难以重置为新分支上的旧提交将重置主分支以及之前的提交。

我希望得到上述问题的答案以及正确的方法(对于git初学者)。

由于 DK

2 个答案:

答案 0 :(得分:1)

  

所以我想签出一个新的分支,然后恢复/硬重置为旧的提交。

实际上,我认为你想以相反的顺序这样做,即:

  • 通过git checkout <SHA-1 hash of earlier commit>
  • 查看之前的提交
  • 通过git checkout -b new_branch
  • 从那里检出新分支

当您在先前提交时签出分支时,您将处于分离的HEAD状态。从那里创建一个新的分支应该留给你想要的东西。

答案 1 :(得分:1)

在我深入了解下面之前(你应该阅读并了解它,因为你最终会需要它),我想提一下,你可以用git checkout -b <commit-id>更容易地做到这一点。这具有检出现有(较旧)提交并生成指向该提交的分支名称的效果。就像执行git branch然后执行git checkout,然后执行下面的git reset一样。

使用git reset

git reset做的事情有点难以解释,但很容易说明,特别是如果我们有颜色......我们不会这样做。所以,让我们在多个部分做这件事。

绘制DAG

首先,我们在存储库中有实际的提交集。这些提交形成一个图形 - 特别是 D 竖立的 A 循环 G raph或DAG,尽管现在我们只需要名称和& #34; DAG&#34;是nice short name。这里要知道的主要事情是每次提交&#34;指向&#34;它的父提交,这些提交是非常可靠和永久的。无论我们做什么,这些提交都将保留在图表中,至少在一段时间内。我们稍后会得到例外(&#34;有些时候&#34;部分)。

如果我们先用左边的提交和后面的(更新的)右边的提示来绘制它,它看起来像这样:

       o <- o
      /
o <- o
      \
       o <- o

(斜杠/代表左下箭头,并非所有字体都可用;反斜杠\代表左上箭头)。每个o节点代表一个提交,箭头代表父指针。这个特定的图有六个提交,没有合并。

每个提交都有一个唯一的SHA-1哈希名称,如a123456...。这些名称永远不会改变:每个名称都特定于其特定的提交。您可以随时使用这些名称,但当然很难输入。 (有时候我会用鼠标来复制并粘贴这些长串的数字。)

标记DAG

因为我们知道先前的提交是向左的,后来的提交是向右的,并且提交指向他们的父母,所以我通常会更紧凑地绘制它。另外,我们通常想知道这些提交所在的分支,所以让我们添加一些分支名称:

      master
        |
        v

     o--o
    /
o--o
    \
     o--o

        ^
        |
     develop

这是六次提交,但现在我们知道他们在哪些分支上:前两个提交 - 在左边,在中间垂直 - 在两个分支上,然后有两个提交仅在master(在顶部)和两个提交仅在develop(在底部)。请注意,分支名称指向 tip-most commit

围绕

移动分支名称

关于分支标签的下一件事是他们移动。提交是坚实和永久的,但标签就像小鸟,从承诺提交。通过向develop再添加一次提交,让图表更大一点,看看标签会发生什么:

      master
        |
        v

     o--o
    /
o--o
    \
     o--o--o

           ^
           |
        develop

我们走了:它感动了!它仍然指向提示提交,但提示是我们刚刚添加的提示。

添加新标签(新分支)

现在,让我们在此图表中添加一个 new 标签 - 一个新分支。我也将新标签指向develop的提示。为了腾出空间,我会将现有的标签画在右边,而不是在上方和下方,但请记住这些是可移动的标签。

     o--o      <-- master
    /
o--o
    \
     o--o--o   <-- develop

           ^
           |
          new

使用git reset

现在,假设我已完成git checkout new以便我在分支new上,请查看git reset对标签的作用。具体来说,让我们进行旧的提交并获取其编号,例如fdeee3df9f54372c31506eb24f2b7f2339ba21ec(此特定数字是Git版本2.8.1):

$ git branch new
$ git checkout new
Switched to branch 'new'
$ git reset --hard fdeee3df9f54372c31506eb24f2b7f2339ba21ec
HEAD is now at d95553a Git 2.8.1

Git本身的存储库图形太大而无法绘制,但假设我在一个较小的存储库中执行此操作,就像现在只有七次提交的存储库一样(当然哈希不再是fdeee3d... )。那我现在可能有这个:

     o--o      <-- master
    /
o--o
    \
     o--o--o   <-- develop

     ^
     |
    new

(假设我给了Git正确的哈希)。如果我向Git提供存储库中第一个提交的哈希值,我会得到:

     o--o      <-- master
    /
o--o
    \
^    o--o--o   <-- develop
|
new

git reset移动分支标签

这里的要点是git reset正在做的是移动分支标签

由于我在分支new上,git reset移动的标签为new

git reset

有点小心

如果我现在去git checkout develop怎么办?git reset它指向一步呢?也就是说,我说图表看起来像这样:

     o--o      <-- master
    /
o--o
    \
^    o--o--o
|       ^
new  develop

请注意,不再有任何箭头指向过去最常提交分支develop的内容吗?

当发生这种情况时,该提交现在已被放弃&#34;或者&#34;不受保护的&#34; (更精确的术语是未引用)。 1 不受保护的提交符合垃圾收集的条件。 git gc命令(根据需要自动调用,因此您通常不必运行它)将找到这些被遗弃的剩余物并回收它们以恢复磁盘空间。

最后,在git reset之后,在develop上删除额外的提交后,Git会真正将其删除,我们会有:

     o--o      <-- master
    /
o--o
    \
^    o--o
|       ^
new  develop

也就是说,我们将回到六次提交。

分支名称当然保护其分支的提示提交 - 但它也保护了提示中的所有提交,因为在Git中,我们可以始终遵循箭头,并且提交指向它们的父提交(向左,在这些图中)。我们可以通过从名称开始,按箭头到提交,并遵循提交来达到任何提交。箭头到其他提交 - 所有提交都可到达,因此受到保护并永远保留在DAG中。

因此,您必须至少对git reset小心一点,以确保您拥有某些标签 - 某些分支名称,通常仍然指向您要保留的提交。制作一个新的分支名称并移动它,可以保证您的确定。

git reset --hard

要更加小心

所有 git reset移动分支标签时,--hard重置也会执行其他操作:它会删除索引/暂存区域和工作树中的工作,通过将那些重置为相同的提交,您git reset移动分支标签。通常情况下,就像你的情况一样,这正是你想要的。

事实上,有时您想要移动分支标签,但想要重置索引和工作树。在这种情况下,您可以在不命名特定提交的情况下运行git reset --hard。 Git将&#34;移动&#34;分支标签从旧提交到...现在无论在哪里。也就是说,它实际上保持在原地。然后Git将继续重置索引和工作树,即消除你所做的任何改变。如果您正在处理代码并且已经决定重新开始,那么这就是您想要的:&#34;将所有内容恢复到最近提交时的状态。&#34;使用git reset --hard即可。它仍会移动分支标签,但是将移动到的位置,意味着您只能看到&#34 ;重置索引和工作树&#34;效果。

1 幸运的是,Git通常使用Git调用的 reflogs 来保持每个正常提交半保护至少30天。每个分支都有自己的reflog,并且HEAD也有一个大的reflog,默认情况下,这些记录会记住提交ID 30到90天。只要reflog记住 - 引用 - 提交ID,就可以保护提交免受垃圾回收。