TFS:合并最佳实践

Cap*_*mic 46 version-control tfs

我们有一个标准的分支架构,我们为每个团队建立了一个开发分支,一个共同的集成分支(所有开发分支都是分支的)和生产分支从Integration分支.

在开发阶段,我向开发分支做了很多提交.在阶段结束时,我将我的更改合并到集成中,然后合并到生产中.

将每个提交单独合并,复制原始提交描述和链接到原始任务是否有意义?另一个选择当然是使用单个合并操作一次合并所有提交.我的问题的原因是第一种方式需要很多时间.我没有在TFS中看到任何将合并链接到其他分支到原始提交的自动化工具.

我想听听您对最佳做法的看法.

Ric*_*erg 75

  1. 来自Dev* - > Integration and Integration的合并 - >生产应始终是"复制"合并.这是保护下游分支稳定性的最安全方法.
    1. 首先在另一个方向合并(例如Integration - > Dev2)以从目标分支获取最新的更改.
    2. 如果存在冲突,请根据具体情况处理差异.AcceptMerge(自动或手动)通常是期望的结果,但有时您会想要保持一个或另一个分支的副本不变.
    3. 使用源分支(在我们的案例中为Dev#2)来完全合并,响应和稳定这些更改.
    4. 合并到所需的方向(例如Dev2 - > Integration).将所有冲突解决为AcceptTheirs [又名"从源头复制"].
    5. 确保步骤#1-4之间的目标分支没有变化.如果Dev分支早期和经常接受合并,那么在这个希望很短的过程中锁定目标分支应该不会很麻烦.如果你因为某种原因预期死亡的"大爆炸"合并,那么锁定会阻止其他团队并行做同样的事情,所以你可能不得不反复重复步骤#1-4直到你准备好了.
  2. 尽可能"赶上"合并.也就是说,以与签入时相同的顺序合并事物.如果变更集10,20和30是从A - > B合并的候选者,那么这些合并范围中的任何一个都是"追赶:"10~10,10 ~20,10~30.跳过#10的任何变更集范围都被称为"樱桃挑选".一旦你开始采摘樱桃,你会遇到一些危害:
    1. 您不能使用上面描述的合并向下,复制模型.仅此一点,Laura Wingerd会说你跳过路边.
    2. 如果您之前触摸了范围中触摸的任何文件,则必须进行3向内容合并,以便仅传播樱桃挑选的差异.没有差异工具是完美的; 你添加的非零风险是带来超过预期的代码,意外覆盖目标中的更改,引入两个分支分歧的逻辑错误等.
    3. 您正在推广到所谓的更稳定分支的一组更改表示以前从未构建或测试过的配置.你可以对目标分支的最终状态做出正确的猜测."我正在合并影响模块Foo的所有变化,我在Dev中测试了新版本的Foo,这就是Foo在Integration中的表现,对吧?" 当然......也许......如果你可以追踪你头脑中的每一个依赖(包括你在测试Dev时可能在Integration中发生的一切变化).但是,您的SCM工具链无法知道或验证这些猜测.
    4. 特别是在TFS中,涉及命名空间更改的樱桃挑选只是要求被烧毁.如果您的版本范围和/或路径范围排除了重命名的来源,它将作为分支而来.如果您排除目标,它将删除.如果你的路径范围不包括取消删除的根,你将得到神秘的错误.如果您的范围跨越取消删除和重新删除之间的时间,即使您没有包含取消删除本身,也会在目标中显示"幻像"文件.如果合并Moves并且所有路径和版本范围都正确,但是这样做不正确,即使所有候选变更集都已用尽,也可能最终得到与源名称不同的目标名称.我确信现在还有更多方法让这个组合出现问题,而现在还没有想到......只要相信我.
  3. 在合并之前始终执行目标分支.最高安全性的高级版本:将要合并的工作区同步到Tip上或附近的特定变更集编号,然后[追赶]合并到相同的变更集.这样做可以避免一些潜在的问题:
    1. 合并到陈旧的代码中,产生令人困惑的3向差异,这些差异似乎可以消除您在Tip上看到的变化.[你最终会让他们回到Checkin + Resolve,但是当你可以避免两者时,没有理由通过两个有风险的差异]
    2. 必须通过冲突解决过程两次:一次在Merge上,一次在Checkin上.在一般情况下没有办法避免这种情况,但是大多数情况下,Merge + Resolve同时进行的更改#与您在工作区中遇到的更改数量相比很小,可能需要几天或几周才能完成.日期.
  4. 除非你真的知道自己在做什么,否则不要通过标签(或工作区)进行合并.让我们回顾一下TFS标签提供的功能,然后分析为什么每个标签都不适合安全和一致的合并.
    1. 标签可以代表多个时间点.如果标签代表VCS的一致快照 - 并且始终如此 - 那么它与日期或变更集#相比没有技术优势.不幸的是,很难判断标签是否实际上是一致的.如果不是,按标签合并可能会导致:
      1. 无意中挑选樱桃,如果范围以标签开头,该标签指向第一个候选人之前的某个项目
      2. 无意中排除,如果范围以指向项目的标签开始@在范围结束之前的时间
      3. 无意中排除,如果范围以标签指向范围开始之前的某个项目结束
    2. 标签版本规范代表一组特定的项目.它们可用于故意排除纯递归查询可能会看到的文件和文件夹.此功能也是Merge操作的不匹配.(再次,如果你没有需要这种能力,你没有招致取得对日期及任何变更以下的风险.)
      1. 标签中不存在的项目将被简单地忽略,而不是合并为待处理的删除.与目前为止所涉及的一些边缘情况不同,这是一个很大的问题,很可能在主流情景中发生,但大多数人都错过了.[因此,TFS 2010增加了对标签内已删除项目的支持.]
      2. 无意中樱桃采摘,如果您在标签上添加了一段时间但由于上述副作用之一而被排除在先前合并之外的标签.
      3. 有意樱桃采摘.这个功能为Merge带来的全部优势是打破我们的一个指导方针,显然这根本不是一个好理由.此外,它会导致文件级别的樱桃采摘,这比变换集中的"普通"樱桃采摘更加危险.
    3. 标签具有友好的可自定义名称,所有者和评论.因此,我们有一个纯粹的可用性差异与日期/变更集; 没有赋予技术优势.但即使在这里它也没有它看起来那么有吸引力.TFS对UI中的实际表面标签没有太大作用,而您可以在整个地方看到变更集注释.所有者查询很快(服务器端),但大多数其他搜索都很慢(客户端),除非您知道确切的标签名称.管理设施几乎不存在.没有更改日志或审核,只有时间戳.总之,这些几乎没有理由放弃变更集提供的担保.
  5. 始终立即合并整个分支.合并文件或子树有时很诱人,但最终仅仅是一种新的幌子.
  6. 未雨绸缪.不幸的是,在TFS中重新托管分支是一个痛苦的话题.有时它是艰苦的,有时它只是几步,但它从来都不明显 ; 没有内置命令(直到2010年).在2005/2008年将其拉下来需要非常深入地了解您当前的分支结构,所需的结构以及如何滥用各种TF命令的副作用.
  7. 不要在分支内部创建分支.例如,有时建议使用分支和合并作为在松散耦合的项目之间维护公共模块或二进制文件的方法.我认为这不是一个非常好的建议 - 更好的是让你的构建系统正确地完成它的主要工作,而不是将你的源代码控制系统搞砸到做一些它不是真正想做的事情.无论如何,这种"共享"策略与项目本身非常冲突,它们存在于更广泛的分支层次结构中,用于SCM目的.如果你不小心,TFS很乐意让你在版本控制项之间创建任意的多对多分支关系.祝你好运排序(我曾经不得不为顾客做这件事,不漂亮.)
  8. 不要独立地在两个分支中创建具有相同相对路径的文件; 使用Merge来分支它们或者你将花费数小时来追逐命名空间冲突.(2010年不适用)
  9. 不要在其他项目曾经存在的路径上重新添加文件.无论旧项目是重命名/移动,还是简单删除,您将在合并时遇到有趣的挑战; 至少,它需要两个Checkins才能完全传播.(2010年不适用,虽然经验仍有所下降;只需要1次登记,项目内容保留,但名称历史记录在该分支和所有下游分支)
  10. 除非你知道你在做什么,否则不要使用/ force标志.所有/强制合并都是有效的选择,导致非常相似的风险(代码在Resolve过程中丢失等).
  11. 除非你真的知道你在做什么,否则不要使用/ baseless标志.你错过了删除 - 类似于标签,除了重命名总是变成分支而不是在不幸的边缘情况下.您没有获得任何借记/信用保护.最可怕的是,你将创造新的分支关系.有时.(没有向用户显示关于每个目标项是新的,旧的具有新关系还是旧的具有现有关系的反馈)
  12. 尽可能避免/丢弃(和等效的,AcceptYours分辨率).放弃一些变更集只接受后续变更集是另一个挑选樱桃的名字:)
  13. 一般来说,请小心你的决议.除了对手头合并的影响之外,每个都有独特的下游效应.
    1. 接受他们是一种快速而有效的方式来获得"复制"合并,如第一个指南中所倡导的那样.如果您在其他场景中也使用它,请记住您只是告诉TFS使文件内容相同.您告诉它这两个文件与版本控制POV 完全同步.也就是说,一旦您签入AcceptTheirs,对目标文件的任何先前更改(可能会以相反方向合并)将不再被视为候选人.
    2. 请注意,其结果内容与源文件相同的AcceptMerge(自动或手动)将被服务器视为AcceptTheirs.在Checkin webservice协议中没有区别.
    3. 涉及重命名时使用AcceptYours会扭曲你的大脑.您很快就会遇到"相同"项目在不同分支中具有不同名称的情况.假设你有充分的理由首先放弃更改,这种现象本身并不是不安全的 - 实际上,可能有必要避免构建中断或对makefile进行一次性自定义.它只会让人感到困惑,并且很可能会破坏你所拥有的任何自动化脚本,这些脚本假设树结构在分支之间是一致的.
    4. AcceptMerge是原因的默认值.它有时会导致更多版本冲突而不是严格必要的版本冲突,但在需要真正合并时是最安全的选择.(例如,主要准则的第1步"合并,复制".)只要您遵循其他准则,需要手动注意的合并数量应该下降 - 如果您来自采摘樱桃的工作流程很重要.
  14. 错误应该链接到实际修复的变更集.如果您以后需要钻入下游分支以查看错误修复的传播时间,地点(以及可能的方式),那就是纯粹的源代码控制功能.不需要用额外的行李污染工作项,更不用说改变你从根本上执行合并的方式了.在2005/2008中,您可以使用'tf merges'命令或第三方UI(如Attrice SideKicks)遍历合并历史记录.2010年,您将获得Visual Studio内置的漂亮可视化. MSDN上的说明和屏幕截图.

  • 我有一种感觉,用git解释的同样的东西会减少80%的单词同样的结果!我坦言不明白TFS与SVN相比,Git,Mercurial地狱甚至CVS似乎更好!不要误会我的意思,我绝对喜欢TFS的任务项目,使用正确的模板它很精彩......但我从来没有遇到过源控制系统那么多麻烦.使用VPN在wan上部署它,每次提交都会成为S&M会话出错! (11认同)

Ger*_*osz 5

我总是只将一系列提交合并到集成分支中,只指定我合并的变更集的范围.

与开发阶段的个别工作项目相关的工作项目是开发阶段工作项目.我认为没有必要将它们推广到集成或发布.

您尚未指定记录客户的错误/功能请求的位置.如果您将这些分配给发布分支,您可能正在为开发分支创建其他更详细的工作项,并且在合并时,您只需将已修复的所有问题标记为已合并的分支.

所以总结一下,我认为没有理由不进行批量合并.