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

时间:2011-03-09 19:03:18

标签: git version-control git-rebase git-merge

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

5 个答案:

答案 0 :(得分:53)

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

  • 天才
  • 将军
  • 电脑黑客

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

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

他们都同意,在接下来的几天里,故事就是这样:

天才

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

一般

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

电脑黑客

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

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

以下是故事:

天才

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

但是日志显示的是,在时间线上混合了各种不同想法的提交。一位读者无法通过阅读提交时间线来真正理解进化,提交的推理。

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

一般

将军的想法:分而治之!

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

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

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

电脑黑客

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

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

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

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

所有人都很高兴。

答案 1 :(得分:26)

  

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

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

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

     #--#--#--#--*-----*-----------------*---#---\         Branch B
    /           /     /                 /         \
---#-----#-----#-----#-----#-----#-----#-----#-----*       Branch A

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

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

                             #--#--#--#--#---\         Branch B
                            /                 \
---#---#---#---#---#---#---#---#---------------*       Branch A

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

答案 2 :(得分:11)

你做一个rebase主要是为了在远程分支(你只是获取)的顶部重做你的本地提交(你尚未推送的那个),以解决任何冲突本地(即在你把它们推回上游回购之前。) 请参阅“git workflow and rebase vs merge questions”,并且非常详细:“git rebase vs git merge”。

但是,rebase不仅限于这种情况,并且结合“--interactive”,它允许一些本地重新订购和清理你的历史。另请参阅“Trimming GIT Checkins/Squashing GIT History”。

  

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

  • 在集中式VCS中,重要的是永远不要丢失历史,它应该确实反映“代码开发的所有方式”。
  • 在分布式VCS中,您可以在 publishing 某些分支到上游之前进行所有类型的本地实验,但保留所有内容的意义不大>在历史中:并非每个人都需要克隆并查看所有分支,测试,替代方案等。

答案 3 :(得分:0)

如果你在公共存储库上犯了一个错误,并且还没有人分叉/合并/撤消它,你可以节省面子和混淆:

git reset --hard [SHAnumber]

git rebase -f master

git push -f origin HEAD:master

清空垃圾桶:

git gc

答案 4 :(得分:0)

整理历史记录是在合并中使用rebase的关键,这非常有价值。

git历史记录有什么用,它可以准确反映过去的每个代码更改?您是否需要某种东西来进行某种认证工作?如果不这样做,为什么要这样?真实发生的过去是混乱且难以理解的。我的意思是,为什么不在编辑文件时还包含您写的然后删除的每个字符?

您将使用git历史记录的最常见方法是阅读它。 查找哪个提交引起了问题并浏览文件的不同版本可能是两个最常见的用例。 当您的git历史记录很简单(而且很干净!)时,这两个用例都变得更加简单和方便。

也许比使用rebase与团队的其他成员共享更改更为重要,每个成员都应该使用rebase将其更改格式化为独立的提交的逻辑集合。 开发并非自然而然地发生在彼此直接遵循的逻辑步骤中。 有时,您只是因为一天结束而不得不在分支上推动提交,所以您必须走了。 将此类信息放入您的git历史记录中纯属噪音。 我通常会压缩一项功能,该功能将20次提交减少到一两次,因为毫无意义地显示出最终没有成为成品的一部分。

即使您的功能的开发历史是一团糟,您也可以而且绝对应该制作一个utopic git历史。 您第一次以正确的顺序正确处理了所有事情,在第一天就完成了功能A,在第二天就完成了功能B,没有错误或临时打印语句。 你为什么要那样做? 因为对于某些人来说,阅读您的更改更容易理解。

如果您将此想法与git bisect结合使用,则整理您的主历史记录以仅包含通过当时定义的所有测试的提交会变得更加有用。 找到bug的起点很简单,因为git bisect可以正常工作。 如果您使用合并并将每个分支的整个开发历史记录上载到master,那么bisect实际上没有帮助的可能性。