我们有一个 Current 分支,主要开发发生在其中。一段时间以来,我一直在一个单独的分支中进行某种实验性的工作。换句话说,我将所需的内容从当前分支分支到实验分支。在工作时,我会定期将 Current 合并到 Experimental 中,这样我就可以得到其他人所做的更改,这样我就可以确定我所做的工作可以与他们的更改配合使用。
我现在想合并回 Current。首先,我将 Current 合并到 Experimental 中,进行编译并确保一切正常。所以在我看来,实验和当前应该“同步”。但是当我尝试将 Experimental 合并回 Current 时,我遇到了一大堆冲突。但我认为当我将 Current 合并到 Experimental 中时,我已经解决了这些问题。
到底是怎么回事?我完全误解了什么吗?我怎样才能顺利地做到这一点?真的不想经历所有这些冲突......
We have a Current branch where the main development happens. For a while I have been working on something kind of experimental in a separate branch. In other words I branched what I needed from the Current branch into an Experimental branch. While working I have regularly merged Current into Experimental so that I have the changes others have made, so that I am sure what I make work with their changes.
I now want to merge back into Current. First I merged Current into Experimental, compiled and made sure everything was working. So in my head, Experimental and Current should be "in sync". But when I try to merge Experimental back into Current, I get a whole bunch of conflicts. But I thought I had already kind of solved those when I merged Current into Experimental.
What is going on? Have I totally misunderstood something? How can I do this smoothly? Really don't want to go through all of those conflicts...
发布评论
评论(3)
当您单击单个冲突的“解决”时,摘要消息会显示什么内容?如果您从 Current 合并 ->实验是在没有大量手动工作的情况下完成的,它应该类似于“X 源,0 目标,Y 两者,0 冲突”。换句话说,目标(当前)文件中不存在源分支副本(实验)中未包含的内容块。您可以安全地使用“自动合并全部”按钮。
注意:无论如何,AutoMerge 应该是安全的。它的优化是为了对早期预警持保守态度,而不是为了解决每个案例的能力。但我认识到,我们中的许多人(包括我自己)喜欢在出现任何问题时启动合并工具。在我所描述的场景中,即使是最不安的人也可以高枕无忧。
为什么会发生冲突呢?如果摘要消息不是那么简洁又该怎么办?干燥?很高兴你问:)简短的回答 - 因为确定相关文件的共同祖先(“基础”)的计算很大程度上取决于它们之间先前合并冲突的解决方式。简单示例:
必须将此事件序列标记为冲突。 B\foo.cs;4 和 A\foo.cs;2 之间最接近的共同祖先可以追溯到步骤 1,从那时起双方都发生了明显的变化。
人们很容易说 A & B 在步骤 4 之后保持同步。(更准确地说:步骤 5 合并的共同祖先是版本 #2)。成功的内容合并肯定意味着 B\foo.cs 包含迄今为止所做的所有更改吗?不幸的是,有很多原因您不能假设这一点:
一般性:并非所有冲突都可以自动合并。您需要适用于这两种情况的标准。
正确性:即使自动合并成功,它也并不总是生成有效的代码。当两个人将相同的字段添加到类定义的不同部分时,就会出现一个典型的例子。
灵活性:每个源代码管理用户都有自己喜欢的合并工具。他们需要能够在最初的 Resolve 决策 [“有一天需要以某种方式合并内容”] 和最终的 Checkin [“这里,这有效”] 之间继续开发/测试。
架构:在像 TFS 这样的集中式系统中,服务器除了自己的数据库 + API 的验证要求之外不能信任任何东西。只要输入符合规范,服务器就不应该尝试区分如何执行各种类型的内容合并。 (如果您认为到目前为止的场景很容易区分,请考虑:如果 AutoMerge 引擎有错误怎么办?如果恶意客户端直接使用任意文件内容调用 Web 服务怎么办?这里只是触及表面......服务器必须持怀疑态度出于某种原因!)它可以安全地计算的只是您向我发送了一个与源或目标不匹配的结果文件。
将这些要求放在一起,您最终会得到一个设计,该设计将步骤 4 中的操作归为一个相当广泛的类别,其中还包括重叠编辑导致的手动合并、第三方工具提供的内容合并(自动或非自动)以及手动文件。事后编辑。在 TFS 术语中,这是一个 AcceptMerge 解决方案。一旦如此记录,合并规则(tm)就必须承担最坏的情况,以追求历史完整性和未来操作的安全性。在此过程中,您对步骤 4 的语义意图(“将 #2 中对 A 所做的所有更改完全纳入 B”)被简化为几个字节的纯逻辑(“为 B 提供以下新内容 + 处理 # 的功劳”) 2”)。虽然不幸的是,这“只是”一个用户体验/教育问题。当合并规则做出错误的假设并导致代码损坏和数据丢失时,人们会变得更加愤怒。相比之下,您只需单击一个按钮即可。
FWIW,这个故事还有很多其他结局。如果您在第 4 步中选择从源分支复制 [又名 AcceptTheirs],则第 5 步中不会发生冲突。如果您选择 AcceptMerge 解决方案但碰巧提交了与 A\foo.cs 具有相同 MD5 哈希值的文件,则同上;2 。如果您选择“保留目标”[又名“接受您的”],下游后果将再次发生变化,尽管我现在不记得细节了。当您添加其他变更类型(尤其是重命名)、合并比我的示例中更加不同步的分支、挑选某些版本范围并稍后处理孤儿等时,上述所有内容都会变得非常复杂......
编辑:命运就是如此,其他人刚刚在 MSDN 论坛上问了完全相同的问题。由于我的本性,我给他们写了另一个长答案,但结果却完全不同! (虽然显然触及相同的关键点)希望这有帮助:http://social.msdn.microsoft.com/Forums/en-US/tfsversioncontrol/thread/e567b8ed-fc66-4b2b-a330-7c7d3a93cf1a
When you click Resolve on an individual conflict, what does the summary message say? If your merges from Current -> Experimental were completed without major manual work, it should be something like "X source, 0 target, Y both, 0 conflicting." In other words, there are no content blocks in the target (Current) file that aren't already in the source branch's copy (Experimental). You can safely use the AutoMerge All button.
Note: AutoMerge should be safe regardless. It's optimized to be conservative about early warnings, not for the ability to solve every case. But I recognize that many of us -- myself included -- like to fire up the merge tool when there's any question. In the scenario described, IMO, even the most skittish can rest easy.
Why is there a conflict at all? And what if the summary message isn't so cut & dry? Glad you asked :) Short answer - because the calculation that determines the common ancestor ("base") of related files depends heavily on how prior merge conflicts between them were resolved. Simple example:
TFS must flag this sequence of events as conflicting. The closest common ancestor between B\foo.cs;4 and A\foo.cs;2 lies all the way back at step 1, and both sides have obviously changed since then.
It's tempting to say that A & B are in sync after step 4. (More precisely: that the common ancestor for step 5's merge is version #2). Surely a successful content merge implies that B\foo.cs contains all the changes made to date? Unfortunately there are a number of reasons you cannot assume this:
Generality: not all conflicts can be AutoMerged. You need criteria that apply to both scenarios.
Correctness: even when AutoMerge succeeds, it doesn't always generate valid code. A classic example arises when two people add the same field to different parts of a class definition.
Flexibility: every source control user has their own favorite merge tools. And they need the ability to continue development/testing between the initial Resolve decision ["need to merge the contents somehow, someday"] and the final Checkin ["here, this works"].
Architecture: in a centralized system like TFS, the server simply can't trust anything but its own database + the API's validation requirements. So long as the input meets spec, the server shouldn't try to distinguish how various types of content merges were performed. (If you think the scenarios so far are easily distinguished, consider: what if the AutoMerge engine has a bug? What if a rogue client calls the webservice directly with arbitrary file contents? Only scratching the surface here...servers have to be skeptical for a reason!) All it can safely calculate is you sent me a resulting file that doesn't match the source or target.
Putting these requirements together, you end up with a design that lumps our actions in step 4 into a fairly broad category that also includes manual merges resulting from overlapping edits, content merges [auto or not] provided by 3rd party tools, and files hand-edited after the fact. In TFS terminology this is an AcceptMerge resolution. Once recorded as such, the Rules of Merge(tm) have to assume the worst in pursuit of historical integrity and the safety of future operations. In the process your semantic intentions for Step 4 ("fully incorporate into B every change that was made to A in #2") were dumbed down to a few bytes of pure logic ("give B the following new contents + credit for handling #2"). While unfortunate, it's "just" a UX / education problem. People get far angrier when the Rules of Merge make bad assumptions that lead to broken code and data loss. By contrast, all you have to do is click a button.
FWIW, there are many other endings to this story. If you chose Copy From Source Branch [aka AcceptTheirs] in step 4, there would be no conflict in step 5. Ditto if you chose an AcceptMerge resolution but happened to commit a file with the same MD5 hash as A\foo.cs;2. If you chose Keep Target [aka AcceptYours] instead, the downstream consequences change yet again, though I can't remember the details right now. All of the above get quite complex when you add other changetypes (especially Rename), merge branches that are far more out of sync than in my example, cherry pick certain version ranges and deal with the orphans later, etc....
EDIT: as fate would have it, someone else just asked the exact same question on the MSDN forum. As tends to be my nature, I wrote them another long answer that came out completely different! (though obviously touching on the same key points) Hope this helps: http://social.msdn.microsoft.com/Forums/en-US/tfsversioncontrol/thread/e567b8ed-fc66-4b2b-a330-7c7d3a93cf1a
我以前也遇到过这种情况。当 TFS 将 Experimental 合并到 Current 中时,它会使用硬盘驱动器上的工作区来执行此操作。如果本地计算机上的当前工作区已过期,TFS 将出现合并冲突。
尝试强制获取 Current 以刷新 Current 的本地副本,然后再次尝试合并。
This has happened to me before. When TFS merges Experimental into Current, it does so using the workspaces on your hard drive. If your Current workspace is out of date on your local computer, TFS will get merge conflicts.
Try doing a forced get of Current to refresh your local coppy of Current and try the merge again.
在开始合并之前,您可能有这样的行...
当您从 Current 推送到 Exp 时,您正在将功能 E 合并到实验分支中。
然后,当您从 Exp 推送到 Current 时,您仍然需要合并 F、G 和 H。这可能是冲突的根源。
----回复第一条评论----
您是自动合并还是使用合并工具?
“冲突”的例子是什么?
You probably have lines like this before you start the merge...
When you push from Current to Exp, you are merging feature E into the experimental branch.
When you then push from Exp to Current, you still have to merge F, G, and H. This is where your conflicts are likely rooted.
----Response to 1st comment----
Do you auto merge, or use the merge tool?
What is an example of something that is "in conflict"?