git interactive rebase squash 创建了全新的分支

git interactive rebase squash creates whole new branch

这是我简单直接历史的最后一部分的图片(来自 SourceTree,时间从下到上):

所以,在这种情况下,我要求 SourceTree 对最底部提交 ("Xcode 10.2, Swift 5") 的 children 进行交互式变基,因为我想折叠接下来的两个提交 ("darn, property list encoding" 和 "v1.1.1build24") 合并为一个提交。没有遥控器,所以我可以自由地重写历史并保持它的清洁和信息。

但是当我这样做时,从 "Xcode 10.2, Swift 5" 分支创建了一大堆新提交 - 现有提交链的副本。我不明白为什么,我东奔西跑地把它清理干净。

它不完全是一个新的 "branch"(正如我的问题标题所说);但是通过 "v1.1.2build28" 的现有提交在它们自己的 dead-end 分支线上结束,并且 master 现在有这些新提交,复制这些提交但没有标签和今天的日期。

我的问题是:为什么会这样,我应该怎么做?

如期完成。

"darn, property list encoding" 和 "v1.1.1build24" 被压缩为一个提交。 Git 通过创建一个新提交来实现此压缩,其父项是 "Xcode 10.2, Swift 5" 并且其更改等同于 "darn, property list encoding" 和 "v1.1.1build24".

的更改

"v1.1.1build25" 的父代或基础是 "v1.1.1build24"。现在一个新的提交已经替换了 "v1.1.1build24" 和 "darn, property list encoding"。因此,"v1.1.1build25" 的父项需要是新的提交。否则,"v1.1.1build24" 以上的提交将不再存在于 master。为了将 "v1.1.1build25" 从旧基础移动到新基础,Git 还为 "v1.1.1build25" 生成一个新提交,其父级现在是压缩的提交,其更改等同于"v1.1.1build25"。因此,所有其余后代都被重新创建,因为它们的 parents/bases 已更改。

Git 创建新的提交,就像旧的被替换一样,但旧的仍然存在于存储库中,只是它们不再可以从 master 访问。然而,像 "v1.1.1build25" 这样的标签和像 "temp" 这样的分支仍然指向旧的提交。由于这些旧提交现在不在当前 master 上,因此这些标签和分支在 master 上也看不到。

没有错。这正是 git 的工作原理。 Git rebase 只不过是一个小机器人,它可以为一堆提交创建新版本。

有些人,甚至是文档,谈到 "rewriting history" 简直是糟糕的措辞。在 git 中根本不可能重写历史 - 一旦提交,就永远无法再次更改。 git 变基仅有助于将旧历史 复制 到新版本的历史。但是 - 如果旧历史,就像你的情况一样,有其他标签或分支,它们将继续指向 old 历史,即使在 rebase 之后也是如此。

因此,git 存储库包含大量死分支是完全正常的。有时您可以看到它们(因为其他 tags/branches 仍然引用它们),有时您不能 - 但如果您碰巧记住了 SHA ID,则可以随时引用它们。 (偶尔,git 的垃圾收集器会出现并收集历史上真正死亡的部分,没有任何指向)。

这很棒,因为您不会犯任何错误 (1)。你总是可以简单地 git reset --hard 到历史的某个点,因为历史 永远不会在 git 中被改变 。如果您尝试了变基、合并或其他任何操作,但它没有像预期的那样工作——如果您记住了之前的 SHA(或者如果您标记了它),您可以返回那里。 (如果没有,您可以通过 git reflog 找到它)。在收集垃圾之前,您总是有几天的时间来这样做。

显然这对你不利,因为你有很多标签你也想指向新的历史记录。我在谷歌上搜索了一下,可能有工具可以将它们带到新分支,但我从未使用过这样的工具。试试看,或者当成事实,git 有着不可改变的历史。也许有一天,您会开始喜欢可以毫无风险地进行试验:-)

(1) 真正丢失工作的唯一方法是在您的工作目录中进行更改并且不提交它们。如果您有未提交的更改并进行 reset --hard,它们将永久丢失并且没有人会警告您。