合并和改基实现了相似的目标,但以不同的方式进行。两者都有助于管理与分支机构的合作和与多人的协作,但它们不可互换,如果处理不当,重新建立基础可能是有害的。
重新建立基础是非常复杂的,所以如果我们想要弄明白它的意义,了解git是如何在幕后工作的是很重要的。
Git将您的代码存储为一系列编辑。你可以把它想象成一条向后工作的链条。每次编辑或“提交”都引用上一次提交的ID,并包括与上一次提交相比所做的更改。这个链只存储在您的计算机上;您的Git客户端不会与任何其他Git客户端对话,除非它正在执行FETCH或PUSH命令(Pull命令实际上只是与您的本地分支进行FETCH+MERGE命令),即使那样,它也只是与共享的远程存储库对话。
分支机构更复杂。Git在处理分支时只存储一件事:分支末尾的提交ID。这样,你就可以把它们想象成唱片播放器上的播放头;你把分支头放在一个特定的位置,它就会通过链条往回工作,“播放”你的代码,并到达最终版本。“每当你提交时,你本地的GIT客户端就会自动将播放头前移到新的提交。”
这将创建一个新的合并提交,如果有任何冲突,您必须手动解决它们。Git merge命令将主播放头移动到新的合并提交,并删除功能播放头,因为它不再需要。
功能分支可能希望包括主分支上的更改,特别是在功能需要一段时间才能开发的情况下。
每次您想要处理分支时都被迫经历合并过程是令人恼火的。
Rebase试图解决这些问题,并取得了不同程度的成功。将更改重新设置为您开始分支的位置。整个分支被提升,并传输到当前主分支的末端,在那里它连接到末端。主分支保持不变,并且可以自由地继续接收提交。
但是,提交实际上并没有移动,因为提交是不变的。相反,它们被复制,这会产生新的提交ID。之前的提交被搁置,隐藏在您的Git文件中,但再也看不到了,因为播放头已经移动到了其他地方。
这将打开分支,将当前更改拉入主分支,然后将特征分支重新定位到主分支。
此时,Feature分支中的代码现在是最新的,这是git rebase唯一真正的特性。重设基址不会合并分支,因为它不会创建任何合并提交或移动母版的播放头。
因此,重新建立基址并不能最终解决处理合并的问题,因为无论如何您都需要在最后合并才能更新主分支。不过,最后的实际合并命令应该可以顺利执行,因为重新建立基址的过程需要您在更改中“合并”,这仍然可能导致冲突。如果您仍然希望继续处理分支,则仍然需要“合并”更改。
还记得重新设置副本基础是如何提交并留下搁浅的播放头的吗?如果您使用的是共享代码,这实际上是一个主要问题。假设您创建了Feature分支,并将其推送到您的repo,以便您的同事可以对其进行测试。这完全没问题,但是如果他们中的一个想要从您的分支分支,当您最终重新建立基础时,您最终会得到这样的结果:
您的同事的功能2分支现在正在引用旧的提交链。您的Git客户机无法知道这一点,因为Feature2分支存储在您同事的计算机上。除非您推动更改,否则他们也无法知道您更改了基数。
当您重新建立基础时,它在复制所有提交时并没有复制Feature2分支。即使它可以,它也不会影响你同事的本地Git回购,使一切都不同步。这里的解决方案是将Feature 2重新设置为原址上的Feature,但即使按照Git标准,这也很麻烦,这只是一个非常简单的示例。
如果您的分支需要一段时间才能开发,重新建立基础可以解决“分支综合症”的问题,即您的代码与工作的主代码太过过时,您需要更新它才能继续工作。一般说来,您应该尽量避免这个问题,但是当它出现时,重新设置基址可以修复它。
如果您只是进行小的、增量的每日更改,那么您应该改为在本地主分支上工作,并在准备好推送更改时使用Pull请求。它们使用主题分支模型,专门为在代码被批准进行合并之前存储代码而创建。
但是,如果您每周工作一次,并且最终将发出多个Pull请求并合并多次,那么您可以在代码上工作更长时间,在本地重新建立基础以进行更新,并在结束时执行一个Pull请求,以减少测试和与主管交谈的数量。重新建立基础主要是本地的事情,因此您可以在您的临时分支机构上进行,而无需等待批准。
如果没有其他人依赖于您的分支,您可以在分支合并之前重新建立基础,以使提交历史清晰且一维。不过,有人可能会争辩说,传统的合并虽然更难看,但更容易跟踪和调试,因为合并提交完全是非破坏性的。无论采用哪种方式,都需要在合并更改之前执行重新基址操作,否则您可能会在批准更改之前遇到Master正在更新的问题。