合并到子分支会导致 TFVC 中新的子分支内容被删除,如何修复?
在我工作的地方,我们有一个分支策略,基本上说有一个始终稳定的最顶层的main
(称之为main、trunk,等等),然后是一个项目组,然后是一个项目,两者都有自己的各自的 main
分支(取自“上”一级,更接近最顶层的主分支)。在项目级别,可能会也可能不会对特定功能进行进一步的分支,具体取决于所涉及工作的复杂性。 (例如,无需创建功能分支来修复一些已识别的用户界面文本拼写错误。)一般来说,这种方法效果很好。我们还将数据库层作为更大源代码树的一部分进行源代码控制,因此每个源代码根目录下都有一个数据库结构。
在database
子树中,有一个patch
目录,其中(在大多数分支中)有一个子目录。该目录以 vCurrent
命名(例如,如果 vCurrent 为 2.3 SP1 HF0,则补丁目录将命名为 2.3 SP1 HF0
),并包含将升级数据库的补丁从 vCurrent 到 vFeature 的架构(可能包含数据转换)。这里的 vFeature
是相关分支投入生产的版本;如果开发由于某种原因没有成功,可能是 vNext
、vFuture
或(在极端情况下)vNever
。功能分支通常没有目标发布版本,但可能有目标发布日期。
因此,结构如下所示:
main
database
patch
2.3 SP1 HF0 <--- indicating that "main" is at version 2.3 SP1 HF0
projectgroup1
main
database
patch
2.3 SP1 HF0
project1
main
database
patch
2.3 SP1 HF0
feature1
database
patch
2.3 SP1 HF0
现在,假设在生产中发现了一个严重错误,需要立即修复,结果将 main
推送到版本 2.3 SP1 HF1。或者管理层决定发布一个版本(可能仅发布一个功能分支)以满足市场需求,为我们提供 2.4 SP0 HF0。或者无论如何。版本中未应用的“来自”2.3 SP1 HF0 的补丁可能仍然适用,也可能不再适用,但最重要的是,这必须由负责每个分支的开发人员根据具体情况决定。 因此,将创建一个具有新的当前版本号的新补丁目录,并删除旧的补丁目录,因为它不再相关(通过选中“显示已删除的项目”,仍然可以从源代码管理中获取它,如以及发布分支,因此获取特定版本的内容不是问题)。当将此变更集合并到各自的功能分支时,每个开发人员都应检查其数据库补丁集并根据需要进行更新,以符合来自上游的任何架构更改。
通常,这不是一个大问题,因为对补丁结构的更改是在最顶层的 main
处进行的(同样,它是稳定的)并向下渗透。
但是,如果第二个(对于已发布的)功能分支存在及其自己的数据库补丁集,TFVC 似乎会在 main 的 2.3 SP1 HF0 补丁目录上进行删除操作不考虑第二个功能分支已将内容添加到已删除的目录,并删除这些新补丁以及patch\2.3 SP1 HF0
。这显然是不可取的。
在我看来,功能分支 2 中的情况是一种冲突:合并的一侧说删除,另一侧说从未合并到合并源的新文件。在这种情况下,TFVC 应该靠边站,将其视为冲突,并询问正在进行合并的程序员该怎么做。请注意,该目录下甚至可能存在名称相同但内容不同的文件(这是设计使然)。相反,它只是通过彻底删除目录及其所有内容来彻底删除您的脚下的地毯。
目前,我们主要通过在删除时执行“撤消挂起的更改”来处理此问题,然后手动移动新补丁并删除旧目录。这显然感觉不是最理想的,而且风险极大(所需要的只是一个开发人员在合并来自上游的“较小”更改之前没有检查其全套待处理更改,而他们在本地有新的数据库补丁,并且您已经失去了工作和很多挫折)。
在 TFS 和 TFVC 的范围内工作(所以请不要说“在 DVCS 模式下使用 Git”或类似的内容),是否有办法真正将其呈现为冲突?或者我们是这样吗?运气不好,只能手动处理这种情况?这种情况并不经常发生,但由于分支数量众多,显然存在犯错误的风险。
Where I work, we have a branching strategy that basically says there is a topmost main
(call it main, trunk, whatever) which is always stable, then a project group, then a project, both with their respective main
branches (taken from one level "up", closer to the topmost main). At the project level, further branching for specific features may or may not be done, depending on the complexity of the work involved. (No need to create a feature branch to fix a few identified user interface text typos, for example.) In general, this works well. We also source control the database layer as a part of the larger source code tree, so there is a database
structure under each source root directory.
In the database
subtree, there is a patch
directory with (in most branches) a single child directory. That directory is named from vCurrent
(for example, if vCurrent is 2.3 SP1 HF0, then the patch directory will be named 2.3 SP1 HF0
) and contains patches that will upgrade the database schema (possibly with data transformation) from vCurrent to vFeature. vFeature
, here, is the version in which the branch in question goes production; that might be vNext
, vFuture
or (in extreme cases) vNever
if development doesn't pan out for some reason. Feature branches generally don't have a target release version, but they may have a target release date.
Hence, the structure looks something like the following:
main
database
patch
2.3 SP1 HF0 <--- indicating that "main" is at version 2.3 SP1 HF0
projectgroup1
main
database
patch
2.3 SP1 HF0
project1
main
database
patch
2.3 SP1 HF0
feature1
database
patch
2.3 SP1 HF0
Now, imagine that a critical bug is discovered in production and necessites an immediate fix, with the result of pushing main
to version 2.3 SP1 HF1. Or management decides to do a release (perhaps of only one feature branch) to satisfy market requirements, giving us 2.4 SP0 HF0. Or whatever. Patches "from" 2.3 SP1 HF0 that were not applied in the release may or may not still be applicable, but most importantly, that must be decided on a case-by-case basis by the developer responsible for each branch. Thus, a new patch directory with the new current version number is created, and the old one is deleted because it is no longer relevant (it's still available from source control by checking "display deleted items", as well as in the release drop branch, so getting to the content of a specific release is not a problem). When merging this changeset to their respective feature branches, each developer is expected to look over their sets of database patches and update them as necessary to comply with any schema changes coming from upstream.
Normally, this is not a big problem, as the changes to the patch structure are made at the topmost main
(which, again, is stable) and trickle downwards.
However, if a second (to the released) feature branch exists with its own set of database patches, TFVC will trickle down the delete operation on main's 2.3 SP1 HF0 patch directory seemingly without regard to the fact that that second feature branch has added content to the deleted directory, and delete those new patches along with patch\2.3 SP1 HF0
. This is clearly undesirable.
In my mind, the situation in feature branch 2 is a conflict: one side of the merge says delete, the other says new files that have never been merged to the source of the merge. In that situation, TFVC should step aside, present this as a conflict, and ask the programmer who is doing the merge what to do. Note that there may even be files under that directory with same names but different content (this is by design). Instead, it just pulls the rug out from under your feet by deleting the directory and all its contents outright.
Currently, we deal with this mostly by doing "undo pending changes" on the deletion, then moving the new patches and deleting the old directory manually. This clearly feels suboptimal, as well as being extremely risky (all it would take is one developer not checking in their full set of pending changes before merging the "minor" change from upstream, while they have fresh database patches locally, and you have lost work and much frustration).
Working within the confines of TFS and TFVC (so please don't say "use Git in DVCS mode" or the likes), is there a way to actually have this presented as a conflict? Or are we out of luck and just have to settle for handling this situation manually? It doesn't happen terribly often, but with the large number of branches, there is clearly the risk of a mistake slipping through.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您可以同时使用 git 和 tfs。查找 git-tfs.两全其美。最大的好处是您不必再处理无基数合并。这是你问题的核心。合并时,将冲突建立在共同基础上对冲突双方都是非常有利的。
顺便说一句,git 中没有“dvcs 模式”。
我们对每个功能都进行积极的分支。这是工作流程:
https://plus.google.com/109096274754593704906/posts/R4qkeyRadLR
抛开技术不谈,我希望它能帮助您解决分支机构问题。至少在 tfs 中,如果您手动标记某些开发工作的开始,则可以比较双方的补丁。
You can use both git and tfs at the same time. Look up git-tfs. Get the best of both worlds. The biggest gain is that you won't have to deal with base less merges anymore. This is the core of your issue. When merging it is very beneficial to base the conflicts in the common base to both sides of the conflict.
There is no "dvcs mode" in git, BTW.
We do aggressive branch per feature. This is or workflow:
https://plus.google.com/109096274754593704906/posts/R4qkeyRadLR
Technology aside, I hope it helps you out with your branch issues. At least in tfs, if you manually mark the beginning of some dev effort, you can compare the patches from both sides.