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]

(我认为这是对的),但我看不出这与根本不变基有什么不同?

你的画误导了你。

记住这些事情:

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

如果它有帮助,请将提交视为大而坚固的东西:例如,构成建筑物的砖块和梁。 (就像超大的乐高积木一样,每块积木都有一些连接到其他积木的连接器,我们将积木拼接在一起制作链条。 这些连接是通过哈希 ID 进行的:它们来自子提交并指向父提交。

另一方面,分支名称是非常轻量级的项目。 它们就像便签,你在提交上拍打,然后剥落并在不同的提交上拍打。

所以如果你有这个:

A <-B <-C <-E <-F   <-- integration

G <-H <-I   <-- feature

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

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

通常,我们发现自己处于这样一种情况,即我们有一个像G这样的提交,这本来是可以的,但如果它稍微不同一点,我们会更喜欢它。 我们想要一个新的副本,它类似于GF作为其父级,并且具有与原始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所做的——嗯,它可以做的几件事之一,但这就是我们现在用它做的——是移动分支名称粘性标签。

有一个粘性标签,我们在上面写了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。 我们还可以使用reflogforfeature来查找提交GHI的哈希 ID。 只要我们有哈希 ID 或哈希 ID 的名称,我们就可以找到提交。 (这些 reflog 条目最终会过期 - 它们有一个日期戳,一三个月后,Git 会删除 reflog 条目。

如果我们使用名称feature,但是,我们会找到新副本而不是原始提交。 这使得提交看起来已经改变,只要我们不密切关注并注意到实际上这些是新的提交。

底线是这样的:在我们复制提交之后,如果我们使用git reset放弃原始副本而支持新的和改进的副本,我们将只看到新的和改进的副本,我们可以表现得像提交已经更改一样。 提交没有改变,如果有人真的仔细观察,他们会发现我们的秘密,但如果其他人从来不知道原件,他们就无法发现这些是 廉价的仿冒 改进副本。

git rebase= 樱桃采摘加复位

这给我们带来了结论:git rebase从根本上git cherry-pick一组提交,后跟git reset。 也就是说,我们首先将提交复制到新的和(我们希望)改进的版本;然后我们使用git reset来尝试诱骗每个人使用改进的提交来代替原始提交。

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

从本质上讲,我读到并发现的是,只有当您想删除提交历史记录时,您才会进行变基。Git 重置将更改参考文件中的引用历史记录。

我找到了两者在堆栈溢出上的区别的一个很好的解释:这里

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

最新更新