Git rebase失去了历史,然后为什么会变质呢?

nge*_*art 47 git version-control git-merge git-rebase

在过去的几天里,我一直在考虑与Git进行变革.反驳的大多数论据都说它清理历史并使其更加线性.如果您进行简单合并(例如),您将获得一个历史记录,显示历史记录何时分歧以及何时将其重新组合在一起.据我所知,rebasing删除了所有历史记录.问题是:为什么你不希望回购历史反映代码开发的所有方式,包括它在哪里以及如何分歧?

Ner*_*ian 59

想象一下,你正在制作一个世界统治秘密项目.这个阴谋有三个主谋:

  • 天才
  • 一般
  • 电脑黑客

他们都同意在1周内来到他们的秘密基地,每个人都有一个详细的计划.

作为务实的程序员,计算机黑客建议他们使用Git来存储计划的所有文件.每个人都会分叉初始项目回购,他们将在一周内合并.

他们都同意,在接下来的几天里,故事如下:

天才

他总共做了70次提交,每天10次.

一般

他窥探了同志的回购,制定了战胜他们的策略.他最后一天做了3次提交.

电脑黑客

这位务实的程序员使用了分支机构.他制定了4个不同的计划,每个计划都在一个分支上.每个分支都被重新命名为一个提交.

七天过去了,小组再次见面,将所有计划合并为一个大师.所有人都渴望开始,所以他们都试图自己合并所有的东西.

这是故事:

天才

他合并了General's repo和Computer Hacker的所有变化.然后,作为一个逻辑爱好者,他看了一下日志.他希望看到一个想法的逻辑演变,其中的东西是根据之前的想法构建的.

但是日志显示的是,在时间线上混合了各种不同想法的提交.一个读者无法真正理解进化,只是通过读取提交时间线来提交提交的原因.

所以他结束了一团糟,即使是天才也无法理解.

一般

将军想:分而治之!

所以他把天才的回购合并在他的回购上.他看了看日志,看到了Genius想法中的一堆提交,这是一个明显的进展,直到最后一天.最后一天,将军和天才的想法是混合的.

他正在监视计算机黑客并了解Rebase解决方案.所以他对自己的想法进行了改变,并再次尝试合并.

现在,日志每天都显示出合乎逻辑的进展.

电脑黑客

这位务实的程序员为Genius创意创建了一个集成分支,另一个为General思想创建,另一个为他自己的想法.他为每个分支做了一个改变.然后他合并了所有的主人.

他的所有队友都看到他的日志很棒.这很简单.乍一看是明智的.

如果一个想法引入了一个问题,很明显在哪个提交引入,因为只有一个.

他们结束了征服全世界,他们消失了Subversion的使用.

一切都很开心.

  • +1让我过得开心:D ...没有很好的例子 (2认同)
  • “他对每个分支进行了变基。然后他将所有分支合并到 master 中。” - 他不应该重新设置基础然后一次合并它们吗?我的意思是,合并一个分支后,需要对其他分支进行变基才能获得最简单的历史记录,对吗? (2认同)

pok*_*oke 28

据我所知,rebasing删除了所有历史记录.

那不对.顾名思义,重新定位会改变提交的基础.通常在该过程中不会丢失提交(除了您没有获得合并提交).虽然你关于将开发过程的所有内容保存在历史记录中的论点是正确的,但这往往会导致历史混乱.

特别是当与其他人一起工作时,每个人都在自己的分支上工作,同时要求其他人继续进行某些更改(例如A要求B实现某些东西,以便A可以在他自己的开发中使用该功能),这会导致许多合并.例如这样:

     #--#--#--#--*-----*-----------------*---#---\         Branch B
    /           /     /                 /         \
---#-----#-----#-----#-----#-----#-----#-----#-----*       Branch A
Run Code Online (Sandbox Code Playgroud)

在这个例子中,我们有一个分支单独工作的时间,但不断从原始分支中提取更改(#是原始提交,*是合并).

现在,如果我们在重新合并之前在分支B上进行变基,我们可以得到以下结果:

                             #--#--#--#--#---\         Branch B
                            /                 \
---#---#---#---#---#---#---#---#---------------*       Branch A
Run Code Online (Sandbox Code Playgroud)

这代表了相同的实际更改,但是B被重新设置为A上的一些旧提交,因此不再需要之前完成的B上的所有合并(因为这些更改已经存在于旧的提交中).现在缺少的所有提交都是合并,通常不包含有关开发过程的任何信息.(请注意,在此示例中,您还可以稍后重新设置A上的最后一次提交,以获得直线,有效地删除对第二个分支的任何提示)

  • 那么,有些数据*会丢失,但只有与开发无关的东西?没有理由看到那些额外的合并,因为它们没有提供任何有意义的信息.是对的吗? (3认同)
  • 确切地说,他们基本上提供的唯一信息是它所基于的分支.在重新定位时,您将这些信息间接地放入其他提交中.除此之外,提交只是调整,但既不删除也不改变(内容). (2认同)
  • @SergioPulgarin我从未见过这种行为.保持创作日期,这是重要的.也许你在谈论提交日期? (2认同)
  • 我不能说这个答案虽然被接受,但却是完全正确的:通过历史记录中的合并提交,您还可以找到冲突解决的踪迹:对于每个冲突,您可以检查之前的两个版本是什么以及它是如何解决的合并后的版本。变基时该信息会丢失。不过,为了更清晰的历史记录,我通常更喜欢 rebase。 (2认同)
  • @戳不是真的。重新设定基准后,就没有任何冲突存在的痕迹了。信息是否有用取决于具体情况(实际上通常不是)。 (2认同)

Von*_*onC 12

你做一个rebase主要是为了在远程分支(你只是获取)的顶部重做你的本地提交(你还没有推动的那个),以便在本地解决任何冲突(即在你将它们推回到上游repo之前) ).
请参阅" git workflow和rebase vs merge问题 ",并且非常详细:" git rebase vs git merge ".

但是,rebase不仅限于这种情况,并且结合"--interactive",它允许一些本地重新订购和清理你的历史.另请参阅" 修剪GIT签名/压缩GIT历史记录 ".

为什么你不希望回购历史反映代码开发的所有方式,包括它在哪里以及如何分歧

  • 在集中式VCS中,重要的是永远不要丢失历史,它应该确实反映"代码开发的所有方式".
  • 在分布式VCS,在那里你可以做所有种类的本地实验之前发布你的一些分支的上游,其意义不大,以保持一切历史记录中:不是每个人都需要克隆和看到所有的分支,测试,替代品,等等.