对新分支上的旧提交进行硬重置也会重置 master 吗?
Will doing a hard reset to an old commit on new branch will reset the master as well?
我想看看上一次提交时的设计是什么样的,所以我想签出到一个新分支,然后 revert/hard 重置为那个旧提交。
我对提交还很陌生,不想通过随机试验破坏任何东西,所以在新分支上硬重置到旧提交将硬重置主分支以及之前的提交。
我想知道上述问题的答案以及正确的做法(对于 git 初学者)。
谢谢
dk
so I want to checkout to a new branch and then revert/hard reset to that older commit.
实际上,我认为你想以相反的顺序执行此操作,即:
- 通过
git checkout <SHA-1 hash of earlier commit>
检查早期的提交
- 通过
git checkout -b new_branch
从那里签出一个新分支
当您签出较早提交的分支时,您将处于分离的 HEAD
状态。从那里创建一个新分支应该会给你留下你想要的东西。
在深入探讨以下内容之前(您应该阅读和了解,因为您最终会需要它),我想提一下,您可以使用 git checkout -b <commit-id>
以更简单的方式做到这一点。这具有检查现有(较旧)提交并创建指向该提交的 new 分支名称的效果。这就像执行下面的 git branch
然后 git checkout
然后 git reset
,全部一步完成。
使用git reset
git reset
的作用有点难以解释,但很容易说明,特别是如果我们有颜色...而我们没有。所以,让我们分多个部分来做。
绘制DAG
首先,我们在存储库中有一组实际的提交。这些提交形成了一个图表——特别是 Directed Acyclic Graph 或 DAG,尽管现在我们只需要名字,"DAG" 是一个 nice short name。这里要知道的主要事情是每个提交 "points to" 它的 parent 提交,并且这些提交是非常可靠和永久的。无论我们做什么,这些提交都会保留在图中,至少会保留一段时间。稍后我们将讨论异常("some time" 部分)。
如果我们将较早的提交向左绘制,而较晚的(较新的)向右提交,则它看起来像这样:
o <- o
/
o <- o
\
o <- o
(斜杠 /
代表 down-and-left 箭头,并非所有字体都可用;反斜杠 \
代表 up-and-left 箭头).每个 o
节点代表一个提交,箭头代表 parent 指针。这个特定的图表有六个提交,没有合并。
这些提交中的每一个都有一个唯一的 SHA-1 哈希名称,例如 a123456...
。这些名称永远不会改变:每个名称都特定于它的一个特定提交。您可以随时使用这些名称,但当然它们很难输入。 (有时我用鼠标copy-and-paste这些一长串的数字。)
标记 DAG
因为我们知道早期的提交是向左的,后来的提交是向右的,并且提交指向它们的 parents,所以我通常会把它画得更紧凑。此外,我们通常想知道这些提交在哪些分支上,所以让我们添加一些分支名称:
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
我们开始了:它感动了!它仍然指向 tip 提交,但是那个 tip 提交是我们刚刚添加的那个。
添加新标签(新分支)
现在让我们给这个图添加一个 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 的存储库图表本身太大而无法绘制,但假设我是在一个较小的存储库中完成的,比如现在只有 7 次提交的存储库(当然哈希不再是 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
的 tip-most 提交?
发生这种情况时,该提交现在是 "abandoned" 或 "unprotected"(更准确的术语是 未引用)。1 未受保护的提交有资格进行 垃圾收集 。 git gc
命令(根据需要自动为您调用,因此您通常不会r 必须 运行 它) 会找到这些废弃的剩菜并回收它们以取回您的磁盘 space。
最终,然后,在 git reset
移除 develop
上的额外提交后,Git 将真正删除它,我们将拥有:
o--o <-- master
/
o--o
\
^ o--o
| ^
new develop
也就是说,我们将回到只有六个提交。
当然,分支名称保护其分支的尖端提交,但它也保护尖端处 而非 的所有提交,因为在 Git ,我们始终可以跟随箭头,并将提交点返回(在这些图中向左)到他们的 parent 提交。我们可以通过以名称开始,跟随箭头指向一个提交,然后跟随提交的箭头指向其他提交来到达的任何提交——所有这些提交都是 reachable,因此受到保护并保留在永远的DAG。
因此,您必须至少小心一点 git reset
,以确保您有 一些 标签——通常是一些分支名称——仍然指向你想保留的承诺。创建一个 new 分支名称,然后移动它,保证你没问题。
小心git reset --hard
虽然 all git reset
s 移动分支标签,但 --hard
重置也做了其他事情:它删除了你的 index/staging-area 和在您的 work-tree 中,通过将它们重置为您要 git reset
移动分支标签的 相同 提交。通常情况下,就像您的情况一样,这正是您想要的。
事实上,有时您不想移动分支标签,但确实想要重置您的索引和work-tree。在这种情况下,您可以 运行 git reset --hard
而不命名特定的提交。 Git 将 "move" 分支标签从它的旧提交到 ... 现在的任何地方。也就是说,它实际上停留在原处。然后 Git 将继续重置索引和 work-tree,即清除您所做的任何更改。如果您在代码上工作了一段时间并决定重新开始,这就是您想要的:"set everything back to the way it is in the most recent commit." 使用 git reset --hard
即可。它仍然移动分支标签,但是将它从 从 所在的位置移动到 到 它所在的位置,意味着你只能 看到 "reset the index and work-tree" 效果。
1幸运的是,Git 通常将每个正常提交 semi-protected 保留至少 30 天,使用 Git 调用的 [=130] =]reflogs。每个分支都有自己的 reflog,HEAD
也有一个大的 reflog,默认情况下这些会记住 30 到 90 天的提交 ID。只要 reflog 记住——引用——提交 ID,提交就不会被垃圾收集。
我想看看上一次提交时的设计是什么样的,所以我想签出到一个新分支,然后 revert/hard 重置为那个旧提交。
我对提交还很陌生,不想通过随机试验破坏任何东西,所以在新分支上硬重置到旧提交将硬重置主分支以及之前的提交。
我想知道上述问题的答案以及正确的做法(对于 git 初学者)。
谢谢 dk
so I want to checkout to a new branch and then revert/hard reset to that older commit.
实际上,我认为你想以相反的顺序执行此操作,即:
- 通过
git checkout <SHA-1 hash of earlier commit>
检查早期的提交
- 通过
git checkout -b new_branch
从那里签出一个新分支
当您签出较早提交的分支时,您将处于分离的 HEAD
状态。从那里创建一个新分支应该会给你留下你想要的东西。
在深入探讨以下内容之前(您应该阅读和了解,因为您最终会需要它),我想提一下,您可以使用 git checkout -b <commit-id>
以更简单的方式做到这一点。这具有检查现有(较旧)提交并创建指向该提交的 new 分支名称的效果。这就像执行下面的 git branch
然后 git checkout
然后 git reset
,全部一步完成。
使用git reset
git reset
的作用有点难以解释,但很容易说明,特别是如果我们有颜色...而我们没有。所以,让我们分多个部分来做。
绘制DAG
首先,我们在存储库中有一组实际的提交。这些提交形成了一个图表——特别是 Directed Acyclic Graph 或 DAG,尽管现在我们只需要名字,"DAG" 是一个 nice short name。这里要知道的主要事情是每个提交 "points to" 它的 parent 提交,并且这些提交是非常可靠和永久的。无论我们做什么,这些提交都会保留在图中,至少会保留一段时间。稍后我们将讨论异常("some time" 部分)。
如果我们将较早的提交向左绘制,而较晚的(较新的)向右提交,则它看起来像这样:
o <- o
/
o <- o
\
o <- o
(斜杠 /
代表 down-and-left 箭头,并非所有字体都可用;反斜杠 \
代表 up-and-left 箭头).每个 o
节点代表一个提交,箭头代表 parent 指针。这个特定的图表有六个提交,没有合并。
这些提交中的每一个都有一个唯一的 SHA-1 哈希名称,例如 a123456...
。这些名称永远不会改变:每个名称都特定于它的一个特定提交。您可以随时使用这些名称,但当然它们很难输入。 (有时我用鼠标copy-and-paste这些一长串的数字。)
标记 DAG
因为我们知道早期的提交是向左的,后来的提交是向右的,并且提交指向它们的 parents,所以我通常会把它画得更紧凑。此外,我们通常想知道这些提交在哪些分支上,所以让我们添加一些分支名称:
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
我们开始了:它感动了!它仍然指向 tip 提交,但是那个 tip 提交是我们刚刚添加的那个。
添加新标签(新分支)
现在让我们给这个图添加一个 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 的存储库图表本身太大而无法绘制,但假设我是在一个较小的存储库中完成的,比如现在只有 7 次提交的存储库(当然哈希不再是 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
的 tip-most 提交?
发生这种情况时,该提交现在是 "abandoned" 或 "unprotected"(更准确的术语是 未引用)。1 未受保护的提交有资格进行 垃圾收集 。 git gc
命令(根据需要自动为您调用,因此您通常不会r 必须 运行 它) 会找到这些废弃的剩菜并回收它们以取回您的磁盘 space。
最终,然后,在 git reset
移除 develop
上的额外提交后,Git 将真正删除它,我们将拥有:
o--o <-- master
/
o--o
\
^ o--o
| ^
new develop
也就是说,我们将回到只有六个提交。
当然,分支名称保护其分支的尖端提交,但它也保护尖端处 而非 的所有提交,因为在 Git ,我们始终可以跟随箭头,并将提交点返回(在这些图中向左)到他们的 parent 提交。我们可以通过以名称开始,跟随箭头指向一个提交,然后跟随提交的箭头指向其他提交来到达的任何提交——所有这些提交都是 reachable,因此受到保护并保留在永远的DAG。
因此,您必须至少小心一点 git reset
,以确保您有 一些 标签——通常是一些分支名称——仍然指向你想保留的承诺。创建一个 new 分支名称,然后移动它,保证你没问题。
小心git reset --hard
虽然 all git reset
s 移动分支标签,但 --hard
重置也做了其他事情:它删除了你的 index/staging-area 和在您的 work-tree 中,通过将它们重置为您要 git reset
移动分支标签的 相同 提交。通常情况下,就像您的情况一样,这正是您想要的。
事实上,有时您不想移动分支标签,但确实想要重置您的索引和work-tree。在这种情况下,您可以 运行 git reset --hard
而不命名特定的提交。 Git 将 "move" 分支标签从它的旧提交到 ... 现在的任何地方。也就是说,它实际上停留在原处。然后 Git 将继续重置索引和 work-tree,即清除您所做的任何更改。如果您在代码上工作了一段时间并决定重新开始,这就是您想要的:"set everything back to the way it is in the most recent commit." 使用 git reset --hard
即可。它仍然移动分支标签,但是将它从 从 所在的位置移动到 到 它所在的位置,意味着你只能 看到 "reset the index and work-tree" 效果。
1幸运的是,Git 通常将每个正常提交 semi-protected 保留至少 30 天,使用 Git 调用的 [=130] =]reflogs。每个分支都有自己的 reflog,HEAD
也有一个大的 reflog,默认情况下这些会记住 30 到 90 天的提交 ID。只要 reflog 记住——引用——提交 ID,提交就不会被垃圾收集。