TFS:合并最佳实践 [英] TFS: Merge best practices

查看:24
本文介绍了TFS:合并最佳实践的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们有一个标准的分支架构,每个团队都有一个开发分支,一个通用集成分支(所有开发分支都从这里分支)和生产分支从集成分支.

We have a standard branch architecture where we have a development branch for each team, a common integration branch (from where all development branches are branched) and production branch branched from Integration.

在开发阶段,我向开发分支进行了大量提交.在阶段结束时,我将更改合并到集成,然后再合并到生产中.

During the development phase I make lots of commits into the development branch. At the end of the phase I merge my changes to integration and later on to production.

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

Does it make sense to merge every commit individually, copying original commit description and linking to original task? Another option is of course to merge all commits at once, with a single merge operation. The reason for my question is that the first way takes lot of time. I don't see any automation tools in TFS that would link merge into other branch to original commit.

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

I would like to hear your opinion on best practices.

推荐答案

  1. 从开发*合并 -> 集成和集成 -> 生产应该始终是复制"合并.这是保持下游分支稳定性的最安全方法.
  1. Merges from Dev* -> Integration and Integration -> Production should always be "copy" merges. This is the safest way to preserve the stability of your downstream branches.
  1. 首先向另一个方向合并(例如集成 -> Dev2)以从目标分支中获取最新更改.
  2. 如果存在冲突,请根据具体情况处理差异.AcceptMerge(自动或手动)通常是您想要的结果,但有时您希望保持一个或另一个分支的副本不变.
  3. 使用源分支(在我们的示例中为 Dev #2)来完全合并、响应和稳定这些更改.
  4. 按所需方向合并(例如 Dev2 -> 集成).以 AcceptTheirs [又名从源代码复制"] 的方式解决所有冲突.
  5. 确保步骤 #1-4 之间的目标分支没有变化.如果 Dev 分支接受早期合并通常,就像它应该的那样,在这个希望很短的过程中锁定目标分支不应该是负担.如果您出于某种原因预期大爆炸"合并死亡,那么锁定很有可能会阻止其他团队并行执行相同的操作,因此您可能必须重复执行步骤 #1-4,直到您准备好.

  • 尽可能赶上"合并.也就是说,按照它们被签入的相同顺序合并事物.如果变更集 10、20 和 30 是从 A -> B 合并的候选者,那么这些合并范围中的任何一个都是赶上":10~10, 10~20、10~30.任何跳过 #10 的变更集范围都被称为樱桃选择".一旦你开始采摘樱桃,你就会遇到一些危险:

  • Do "catch up" merges whenever possible. That is, merge things in the same order they were checked in. If changesets 10, 20, and 30 are candidates to merge from A -> B, then any of these merge ranges is a "catch up:" 10~10, 10~20, 10~30. Any changeset range that skips #10 is known as a "cherry pick." Once you start cherry picking you run into a few hazards:

    1. 您不能使用 向下合并,向上复制 上面描述的模型.仅凭这一点,劳拉·温格德就会说你正在跳过路边.
    2. 如果在您的范围内接触过的任何文件之前也被接触过,则您必须进行 3 向内容合并,以便仅传播精选的差异.没有差异工具是完美的;您增加了一个非零风险:带来比预期更多的代码、意外覆盖在目标中所做的更改、在两个分支出现分歧的情况下引入逻辑错误等.
    3. 您正在向据称更稳定的分支推进的一组更改代表了一种以前从未构建或测试过的配置.您可以对目标分支的最终状态做出合理的猜测.我正在合并影响 Module Foo 的所有更改,并且我在 Dev 中测试了 Foo 的新版本,这就是 Foo 在集成中的表现,对吗?"当然......也许......如果你能在你的脑海中追踪每一个依赖(包括在你测试 Dev 时集成中可能发生的所有变化).但是,您的 SCM 工具链绝不会知道或验证这些猜测.
    4. 特别是在 TFS 中,挑选涉及命名空间更改的地方只是要求被烧毁.如果您的版本范围和/或路径范围不包括重命名的来源,它将作为分支出现.如果您排除目标,它将挂起删除.如果您的路径范围不包含取消删除的根,您将收到神秘错误.如果您的范围跨越取消删除和删除之间的时间重新删除,即使您不包括取消删除本身,您也会在目标中出现幻影"文件.如果您将 Moves 与所有路径合并,版本范围是正确的,但这样做是乱序的,即使在所有候选变更集都已用完之后,最终可能会得到与源名称不同的目标名称.我敢肯定,现在还没有想到这个组合出错的更多方法......相信我.
    1. You can't use the merge down, copy up model described above. For that alone, Laura Wingerd would say you're jumping over a curb.
    2. If any of the files touched in your range were also touched previously, you'll have to do a 3-way content merge so that only the cherry-picked diffs are propagated. No diff tool is perfect; you're adding a nonzero risk of bringing over more code than intended, accidentally overwriting changes made in the target, introducing logic bugs where the two branches diverge, etc.
    3. The set of changes you're promoting into the supposedly more stable branch represents a configuration that has never been built or tested before. You can make a decent guess about the final state of the target branch. "I'm merging all the changes affecting Module Foo, and I tested the new version of Foo in Dev, so that's how Foo will behave in Integration, right?" Sure...maybe...if you can track every dependency in your head (including everything that may have changed in Integration while you were testing Dev). But these guesses are in no way known to or validated by your SCM tool chain.
    4. In TFS specifically, cherry picking where namespace changes are involved is just asking to get burned. If your version range and/or path scope excludes the source of a rename, it'll come over as a branch instead. If you exclude the target, it'll pend a delete. If your path scope doesn't include the root of an undelete you'll get cryptic errors. If your range spans a time in between an undelete & re-delete, you'll get "phantom" files appearing in the target even if you don't include the undelete itself. If you merge Moves with all your path & version scopes correct, but do so out of order, it's possible to end up with a different target name than the source name even after all the candidate changesets have been exhausted. I'm sure there are more ways for this combo to go wrong that aren't coming to mind right now...just trust me.

  • 在合并之前始终在目标分支上执行 Get 操作.终极安全的高级版本:将您将合并到提示处或附近的特定变更集编号的工作区同步,然后也[赶上] 合并到同一变更集.这样做可以避免一些潜在的问题:

  • Always do a Get on the target branch before merging. Advanced version for ultimate safety: sync the workspace where you'll be merging to a specific changeset number that's at or near the Tip, then also [catch-up] merge to that same changeset. Doing so avoids a few potential issues:

    1. 合并到陈旧代码中,产生令人困惑的三向差异,这些差异似乎删除您在提示中看到的更改.[您最终会在 Checkin + Resolve 中取回它们,但如果您可以避免两者,则没有理由通过两个有风险的差异]
    2. 必须通过两次冲突解决流程:一次在合并时,一次在签入时.在一般情况下无法避免这种情况,但大多数情况下,与您在工作区中遇到的更改数量相比,合并 + 解决时同时进行的更改数量很少,而工作空间可能需要几天或几周的时间日期.
    1. Merging into stale code, yielding confusing 3-way diffs that appear to remove changes from what you see at Tip. [you'd eventually get them back upon Checkin + Resolve, but no reason to go thru two risky diffs when you can avoid both]
    2. Having to go thru the conflict resolution process twice: once on Merge, once on Checkin. There's no way to avoid this in the general case, but most of the time the # of simultaneous changes made while you Merge + Resolve is tiny compared with the # of changes you'd encounter in a workspace that might be days or weeks out of date.

  • 不要按标签(或工作区)合并,除非您真的很清楚自己在做什么.让我们回顾一下 TFS 标签提供的功能,然后剖析为什么每个功能都不适用于 safe &一致合并.

  • Don't merge by label (or workspace) unless you really really know what you're doing. Let's review the features offered by TFS labels and then dissect why each is inappropriate for safe & consistent merging.

    1. 标签可以代表多个时间点.如果一个标签代表 VCS 的一致快照——并且总是如此——那么它与日期或变更集#相比没有技术优势.不幸的是,很难判断一个标签是否真的随着时间的推移保持一致.如果没有,按标签合并可能会导致:
    1. Labels can represent multiple points in time. If a label represents a consistent snapshot of the VCS -- and was always intended as such -- then it has no technical advantage over a date or changeset #. Unfortunately it's quite difficult to tell if a label is in fact consistent over time. If not, merging by label can lead to:
    1. 无意中的挑选,如果范围以一个标签开头,该标签指向一个项目@比第一个候选提前一段时间
    2. 无意中的排除,如果范围以指向项目的标签开头@范围结束前的时间
    3. 无意中的排除,如果范围以指向项目的标签结束@范围开始前的时间

  • 标签版本规范代表一组特定的项目.它们可用于有意排除纯递归查询否则会看到的文件和文件夹.此功能也不适合合并操作.(同样,如果您不需要此功能,您将承担以下风险,而不会在日期和变更集上获得任何收益.)

  • Label versionspecs represent a specific set of items. They can be used to deliberately exclude files and folders that a pure recursive query would otherwise see. This feature, too, is a bad match for Merge operations. (And again, if you don't need this ability, you're incurring the following risk without gaining anything over dates & changesets.)

    1. 标签中不存在的项目将被简单地忽略,而不是合并为待删除的内容.与目前所涵盖的一些边缘情况不同,这是一个很可能在主流场景中发生但大多数人都错过的大问题.[因此,TFS 2010 添加了对标签内已删除项目的支持.]
    2. 无意中摘取樱桃,如果您向标签中添加了一个已存在一段时间但由于上述副作用之一而被排除在先前合并之外的项目.
    3. 故意采摘樱桃.此功能为 Merge 带来的全部优势是违反了我们的一项准则,因此显然这根本不是一个很好的理由.此外,它会导致在文件级别进行挑选,这比通过变更集进行的普通"挑选更加危险.
    1. Items not present in the label will be simply ignored, rather than merged as pending deletes. Unlike some of the edge cases covered so far, this is a big deal that's quite likely to happen in mainstream scenarios yet most people miss. [As a result, TFS 2010 adds support for deleted items inside labels.]
    2. Inadvertent cherry picking, if you add an item to the label that has been present for awhile but was excluded from prior merges due to one of the aforementioned side effects.
    3. Intentional cherry picking. The whole advantage this feature brings to Merge is to break one of our guidelines, so obviously that's not a good reason at all. Furthermore, it causes cherry-picking at the file level, which is even more dangerous than "ordinary" cherry picking by changeset.

  • 标签具有友好的可自定义名称、所有者和评论.因此,我们有一个纯粹的可用性差异与日期/变更集;没有技术优势.但即使在这里,它也没有看起来那么吸引人.TFS 在 UI 中实际显示标签并没有做太多事情,而您可以在各处看到变更集注释.所有者查询很快(服务器端),但大多数其他搜索都很慢(客户端),除非您知道确切的标签名称.管理设施几乎不存在.没有变更日志或审计,只有一个时间戳.总之,这些都不是放弃变更集提供的保证的理由.
  • 总是一次合并整个分支.合并文件或子树有时很诱人,但归根结底只是换个新幌子来挑剔.
  • 提前计划.不幸的是,在 TFS 中重新创建分支是一个痛苦的话题.有时很艰巨,有时只需几步,但它永远显而易见;没有内置命令(直到 2010 年).在 2005/2008 年完成它需要非常深入地了解您当前的分支结构、所需的结构以及如何滥用各种 TF 命令的副作用.
  • 不要在分支内创建分支.例如,分支 &有时建议将合并作为在松散耦合项目之间维护公共模块或二进制文件的一种方式.我不认为这是一个很好的建议——让你的构建系统正确地完成它的主要工作,比将你的源代码控制系统硬塞进它并不是真正设计来做的事情要好得多.无论如何,这种共享"策略与出于 SCM 目的而位于更广泛的分支层次结构中的项目本身发生了严重冲突.如果您不够小心,TFS 会很乐意让您在版本控制项之间创建任意的多对多分支关系.祝你好运解决这个问题(我曾经不得不为客户做这件事,不漂亮.)
  • 不要在两个分支中独立创建具有相同相对路径的文件;使用 Merge 对它们进行分支,否则您将花费​​数小时来解决命名空间冲突.(2010 年不适用)
  • 不要在其他项目曾经存在的路径上重新添加文件.无论旧项目是重命名/移走,还是干脆删除,您在合并时都会面临有趣的挑战;至少,它需要两个 Checkins 才能完全传播.(2010年n/a,虽然体验还是有些下降,只需要1次签到,项目内容保留,但名字历史在那个分支&所有下游分支)
  • 除非您知道自己在做什么,否则不要使用/force 标志.所有/force 合并实际上都是精心挑选的,导致非常相似的风险(在解决过程中丢失代码等).
  • 除非您真的很清楚自己在做什么,否则不要使用/baseless 标志.你错过了删除——类似于标签,除了重命名总是会变成分支,而不仅仅是在不幸的边缘情况下.您不会获得任何借记/信用保护.最可怕的是,您将创建新的分支关系.有时.(不向用户显示每个目标项目是新的、旧的有新关系还是旧有关系的反馈)
  • 尽可能避免/discard(以及等效的 AcceptYours 解决方案).丢弃一些变更集只是为了接受后续的变更集是樱桃采摘的另一个名称:)
  • 一般而言,请谨慎处理您的决议.除了对手头合并的影响之外,每个都有独特的下游影响.

  • Always merge the entire branch at once. Merging files or subtrees is sometimes tempting, but ultimately amounts to mere cherry-picking under a new guise.
  • Plan ahead. Unfortunately, re-parenting branches in TFS is a painful topic. Sometimes it's arduous, sometimes it's only a few steps, but it's never obvious; there is no built in command (until 2010). Pulling it off in 2005/2008 requires a pretty deep knowledge of your current branch structure, desired structure, and how to abuse the side effects of various TF commands.
  • Don't create branches inside of branches. For example, branching & merging is sometimes recommended as a way to maintain common modules or binaries between loosely coupled projects. I don't think this is very good advice to begin with -- far better to make your build system do its primary job properly, than to shoehorn your source control system into doing something it's not really designed to do. Anyway, this "sharing" tactic clashes terribly with projects themselves live inside a broader branch hierarchy for SCM purposes. If you're not uber careful, TFS will happily let you create arbitrary many-to-many branch relationships between version control items. Good luck sorting that out (I once had to do it for a customer, not pretty.)
  • Don't create files with the same relative path in two branches independently; use Merge to branch them around or you'll spend hours chasing namespace conflicts. (n/a in 2010)
  • Don't re-add files on top of a path where other items used to exist. Whether the old items were Rename/Moved away, or simply Deleted, you'll face interesting challenges at Merge time; at minimum, it'll require two Checkins to fully propagate. (n/a in 2010, though the experience is still somewhat degraded; only 1 checkin is required, item contents is preserved, but the name history is in that branch & all downstream branches)
  • Don't use the /force flag unless you know what you're doing. All /force merges are effectively cherry picks, leading to very similar risks (code getting lost during the Resolve process, etc etc).
  • Don't use the /baseless flag unless you really really know what you're doing. You miss out on deletes -- similar to labels, except that renames always get morphed into branches instead of just in the unlucky edge cases. You don't get any debit/credit protections whatsoever. And scariest of all, you'll be creating new branch relationships. Sometimes. (no feedback is shown to the user as to whether each target items is new, old with a new relationship, or old with an existing relationship)
  • Avoid /discard (and equivalently, AcceptYours resolutions) when possible. Discarding some changesets only to accept subsequent ones is yet another name for cherry-picking :)
  • Be careful with your resolutions in general. Each has unique downstream effects apart from its effect on the merge at hand.

    1. AcceptTheirs 是一个快速的 &正如第一个指南中所提倡的那样,获得复制"合并的强大方法.如果您也在其他场景中使用它,请记住您不是只是告诉 TFS 使文件内容相同.您告诉它这两个文件完全同步来自版本控制 POV.也就是说,一旦您签入 AcceptTheirs,对目标文件所做的任何先前可能以相反方向合并的更改将不再被视为候选文件.
    2. 请注意,其结果内容与源文件相同的 AcceptMerge(自动或手动)将被服务器视为 AcceptTheirs.在 Checkin 网络服务协议中没有发现任何区别.
    3. 在涉及重命名时使用 AcceptYours 会扭曲您的大脑.您很快就会遇到相同"项目在不同分支中具有不同名称的情况.假设您首先有充分的理由放弃更改,这种现象本身并不是不安全的——事实上,可能有必要避免构建中断或对您的 makefile 进行一次性定制.它只会让人类感到困惑,并且很可能会破坏您拥有的任何自动化脚本,这些脚本假设树结构从分支到分支都是一致的.
    4. AcceptMerge 是默认设置是有原因的.它有时会导致比看起来更严格的版本冲突,但在需要真正合并时是最安全的选择.(例如,主要指南的第 1 步向下合并,向上复制".)只要您遵循其他指南,需要手动注意的合并数量就会下降——如果您来自大量挑选樱桃的工作流程.
    1. AcceptTheirs is a quick & powerful way to get a "copy" merge, as advocated in the first guideline. If you use it in other scenarios as well, remember you're not just telling TFS to make the file contents the same. You're telling it that the two files are completely in sync from a versioning POV. To wit, any prior changes to the target file that might've merged in opposite direction will no longer be considered candidates once you checkin an AcceptTheirs.
    2. Note that an AcceptMerge (auto or manual) whose resulting contents is identical to the source file will be considered an AcceptTheirs by the server. There is no differentiation to be found in the Checkin webservice protocol.
    3. Using AcceptYours when renames are involved can twist your brain. You'll quickly end up in a situation where "the same" item has different names in different branches. Assuming you have a good reason for discarding changes in the first place, this phenomenon isn't unsafe per se -- in fact, it's probably necessary to avoid either build breaks or one-off customizations to your makefiles. It's just confusing to humans, and very likely to break any automation scripts you have that assume tree structures are consistent from branch to branch.
    4. AcceptMerge is the default for a reason. It sometimes leads to more version conflicts than seem strictly necessary, but is the safest choice when true merging is required. (E.g. step #1 of the primary guideline "merge down, copy up".) So long as you're following the other guidelines, the number of merges that require manual attention should fall -- dramatically so if you're coming from a workflow that's heavy on cherry-picking.

  • 错误应该链接到实际进行修复的变更集.如果您稍后需要深入到下游分支以查看错误修复的传播时间、地点(以及可能的方式),那么这就是纯粹的源代码控制功能.无需用额外的包袱污染工作项,更不用说从根本上改变执行合并的方式了.在 2005/2008 中,您可以使用tf merges"命令或 Attrice SideKicks 等 3rd 方 UI 遍历合并历史记录.2010 年,您将获得内置于 Visual Studio 中的漂亮可视化.说明和;MSDN 上的屏幕截图.
  • 这篇关于TFS:合并最佳实践的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆