git rebase和git reset之间的区别

时间:2018-09-11 19:50:14

标签: git git-rebase

说我有这个:

A - B - C - E - F    [integration]
 \
  G - H - I          [feature]

在提交I之后,我们以集成为基础:

git fetch origin
git rebase integration

所以我们现在有:

A - B - C - E - F    [integration]
 \
  B - C - E - F - G - H - I          [feature]

然后说我们将特征分支合并到集成中,然后得到:

A - B - C - E - F - G - H - I   [integration]
 \
  B - C - E - F - G - H - I          [feature]

(我认为是正确的),但是我不知道这与不重新定基有什么不同?

2 个答案:

答案 0 :(得分:2)

您的绘画误导了您。

记住这些事情:

  • 提交的“真实名称”是其哈希ID。
  • 每个提交都存储其父提交(对于合并提交)的所有哈希ID。
  • 根本不能更改任何提交,但是可以将提交 复制到新的替换项。

如果有帮助,可以将提交视为坚固的大物件:例如,砖和梁组成建筑物。 (就像超大乐高积木一样,每个积木都有一些与其他积木的连接器,我们将积木插入在一起以形成链。这些连接通过哈希ID:它们来自子提交,并指向父提交。 )

另一方面,

分支名称是重量很轻的商品。它们就像便签一样,您先拍一下,然后再剥下来再拍一次。

所以,如果您有这个:

A <-B <-C <-E <-F   <-- integration
 \
  G <-H <-I   <-- feature

您无法获取第二张图片,因为现有提交G记录了A的哈希ID。您不能拥有一个以G作为其父元素的F。您也不应绘制两次提交,如果可能的话:提交是唯一的东西,只有一个提交G

git cherry-pick复制提交的构建基块

通常,我们发现自己处于G之类的提交状态,这种状态就可以了,但是如果它有所不同,我们会更喜欢它。我们想要一个新的副本,它像 G,但以F作为其父副本,并且也具有与原始G不同的源树快照。让我们将新提交称为G'来与G区别开来,但提醒我们,它非常像 G。我们希望 FG'之间的差异与 AG之间的差异相同,从而也考虑了由于提交B-C-E-F而需要进行的任何更改。所以我们想要的是一个看起来像这样的提交图:

              G'  <-- new-and-improved-feature
             /
A--B--C--E--F   <-- integration
 \
  G--H--I   <-- feature

如果我们然后将提交H复制到新的和改进的 H',然后将I复制到新的和改进的 I',我们得到了:

              G'-H'-I'  <-- new-and-improved-feature
             /
A--B--C--E--F   <-- integration
 \
  G--H--I   <-- feature

git reset移动标签

git reset所做的事情-可以做的几件事之一,但这就是我们现在要处理的事情-移动分支名称sticky-labels。

有一个粘贴标签,上面我们写了feature一词。该粘性标签现在附加到提交I上。但是在新的和改进的设置中,我们仅使用git cherry-pick三次,将G-H-I序列复制到G'-H'-I'序列中。

如果现在我们有Git,将标签feature从提交I上剥离下来,然后将其粘贴到提交I'上,我们将得到:

              G'-H'-I'  <-- feature (HEAD), new-and-improved-feature
             /
A--B--C--E--F   <-- integration
 \
  G--H--I   <-- ORIG_HEAD

要实现这一点,我们运行:git checkout feature; git reset new-and-improved-feature

git reset命令设置此特殊名称ORIG_HEAD来记住feature过去的去向。现在,标签feature已附加到提交I',但是有多种方法可以找到I,包括此ORIG_HEAD技巧。

(我们不再需要“新功能和改进功能”标签,因此我们现在可以将其删除。)

请注意,没有提交已更改。原始G仍在存储库中。运行git log ORIG_HEAD,我们仍然可以看到它,至少直到执行另一个使用ORIG_HEAD来记住其他提交的Git命令为止。我们将看到I,然后是H,然后是G。我们还可以对feature使用 reflog 来查找提交GHI的哈希ID。只要我们具有哈希ID或哈希ID的名称,就可以找到提交。 (那些引用日志条目最终会过期,它们带有日期戳,一三个月后,Git会删除引用日志条目。)

但是,如果我们使用名称feature,则会查找新副本,而不是原始提交。只要我们不密切注意并注意到实际上它们是 new 提交,就可以使好像提交已更改。

最重要的是:我们复制提交之后,如果我们使用git reset放弃原始文档,而使用经过改进的新副本,那么我们只会看到新的和改进的副本,我们可以像那样更改提交内容。提交内容没有改变,如果真的有人仔细观察,他们会发现我们的秘密,但是如果其他人从不了解原著,他们就不会发现这些是廉价仿冒品< / strike>改进的副本。

git rebase =樱桃选择加重置

这使我们得出以下结论: git rebase从根本上说是git cherry-pick的一组提交中的一个,之后是 git reset 。也就是说,我们从复制提交到新的并且我们希望改进的版本开始。然后我们使用git reset尝试诱使所有人使用改进的提交来代替原始提交。

任何仍然拥有原始内容的人都不会上当!如果其他人(其他Git存储库)仍然拥有原始内容,我们必须说服他们切换到新的改进的提交。但是,如果我们是唯一有权访问提交的人,则只需要愚弄自己,这可能会更容易。

答案 1 :(得分:1)

从本质上讲,我已经阅读并发现的是,只有在您想删除提交历史记录时才进行重新设置。 Git重置将更改参考文件中的参考历史记录。

我对堆栈溢出两者之间的区别找到了很好的解释:here

我希望这有助于弄清哪种选择是在哪种情况下工作的最佳工具。