TFS: Combine Best Practices

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

At the development stage, I make many commits to the development branch. At the end of the phase, I will combine my changes in integration, and then in production.

Does it make sense to combine each commit separately, copying the original description of the commit and the relationship with the original task? Another option is, of course, to combine all the commits at once with one merge operation. The reason for my question is that the first path takes a lot of time. I do not see any automation tools in TFS that link the merge to another branch with the original commit.

I would like to hear your opinion on best practices.

+44
version-control tfs
Dec 07 '09 at 15:34
source share
2 answers
  • Merging with Dev * → Integration and Integration → Production should always be a “copy” of a merger. This is the safest way to keep your descending branches stable.
    • First merge in the other direction (e.g. Integration -> Dev2) to get the latest changes from the target branch.
    • If there are conflicts, handle the differences in each case. AcceptMerge (automatic or manual) is usually the desired result, but sometimes you want to take one or the other branch without changes.
    • Use the source branch (Dev # 2 in our case) to fully enable, react and stabilize these changes.
    • Merge in the desired direction (for example, Dev2 → Integration). Resolve all conflicts as AcceptTheirs [aka "copy from source"].
    • Make sure there are no changes in the target branch between steps 1-4. If the Dev branch accepts the merge early and often, as it should be, then it should not be burdensome to block the target branch during this promising process. If you expect a "big bang" to merge death for any reason, there a decent lock will block other teams from doing the same thing in parallel, so you may have to repeat steps 1-4 1-4 until you're ready .
  • "Catch up" merges when possible. That is, combine things in the same order in which they were checked. If changes 10, 20, and 30 are candidates for merging with A → B, then any of these merging ranges is “catching up”: 10 ~ 10, 10 ~ 20, 10 ~ 30. Any change range that # 10 skips is known as "cherry picker." Once you start picking cherries, you will encounter several dangers:
    • You cannot use merge, copy the model described above. Just for this, Laura Wingerd would say that you are jumping over the curb.
    • If any of the files affected by your range has also been affected previously, you will need to perform a three-way merge of the content to propagate only cherry differences. The diff tool is not perfect; you add a non-zero risk of entering more code than expected by accidentally rewriting the changes made to the target, introducing logical errors when the two branches diverge, etc.
    • The set of changes you are pushing into a supposedly more stable branch is a configuration that has never been built or tested before. You can guess the final state of the target branch. "I merge all the changes that affect the Foo module, and I tested the new version of Foo in Dev, so how will Foo behave in integration, right?" Of course ... maybe ... if you can track every dependency in your head (including everything that could have changed in Integration when you tested Dev). But these conjectures are by no means known or endorsed by your SCM toolchain.
    • In TFS specifically, choosing a cherry in which namespace changes occur is just asking for a burn. If your version range and / or path region excludes the renaming source, it will be replaced as a branch. If you exclude the target, it will delay the deletion. If your area of ​​the path does not include the recovery root, you will get cryptic errors. If your range covers the time between recovery and re-deletion, you will get "phantom" files displayed in the target, even if you do not enable undelete itself. If you combine Moves with all your paths and versions, correct, but do it out of order, you can get a different target name than the source name, even after all changes to the candidate set have been exhausted. I am sure that there are more ways to make this combination go wrong than it doesn’t come to mind ... just trust me.
  • Always do Get on the target branch before merging. An extended version for maximum security: synchronize the workspace in which you will merge with a specific change set number, which is next to or near the tooltip, and then [catch up] the merge with the same set of changes. This avoids several possible problems:
    • Merging with legacy code, leading to confusing tripartite differences that seem to eliminate the changes you see in the tooltip. [you will eventually return them back to Checkin + Resolve, but there is no reason to go through two risky differences when you can avoid both]
    • You must go through the conflict resolution process twice: once on Merge, once on Checkin. There is no way to avoid this in the general case, but in most cases # the simultaneous changes made while you Merge + Resolve are tiny compared to C # changes you encountered in the workspace, which may be days or weeks from date .
  • Do not merge by label (or workspace) unless you really know what you are doing. Let's look at the functions offered by TFS tags, and then analyze why each of them is not suitable for safe and consistent merging.
    • Labels can represent multiple points in time. If the tag is a consistent VCS snapshot and has always been designed as such, then it does not have a technical advantage over the date or set of changes #. Unfortunately, it’s pretty hard to say if the label really agrees over time. If not, label merging can result in:
      • Incorrect selection of cherries if the range starts with a label pointing to the @ element for the time before the first candidate.
      • Unintended exception if a range starts with a label pointing to the element @ time before the end of the range
      • Unintended exception if the range ends with a label pointing to the @ element at a time before the start of the range
    • Versionpecs labels are a specific set of elements. They can be used to deliberately exclude files and folders that a recursive query would otherwise see. This feature is also a bad match for merge operations. (And again, if you do not need this ability, you are at the next risk of not getting anything from dates and sets of changes.)
      • Items that are not in the label will simply be ignored, not merged as pending removal. Unlike some of the regional cases considered so far, this is a big deal, which is likely to happen in the main scenarios, but most people will miss. [As a result, TFS 2010 adds support for deleted items within labels.]
      • Wrong cherry selection if you add an item to a label that has been present for some time but has been excluded from previous mergers due to one of the above side effects.
      • Intentional picking cherries. Merge brings all the benefits of this feature to break one of our recommendations, so this is obviously not a good reason. In addition, it causes file-level cherry picking, which is even more dangerous than the “normal” cherry picker for a set of changes.
    • Shortcuts have friendly custom names, owners and comments. Thus, we have a net difference in usage compared to dates / sets of changes; technical advantage not available. But even here it is not as attractive as it seems. TFS does not do much to actually draw labels in the user interface, while you can see comments on changes all over the place. An owner’s request is fast (server-side), but most other requests are slow (client-side) if you don’t know the exact label name. Management tools are practically absent. No changes or audits, just a timestamp. In general, this is unlikely to warrant a waiver provided by sets of changes.
  • Always merge the entire branch at once. Merging files or subtrees is sometimes tempting, but ultimately comes down to a simple set of cherries under a new look.
  • Plan ahead. Unfortunately, retraining branches in TFS is a painful topic. Sometimes it's hard, sometimes it's just a few steps, but it is never obvious; no built-in command (until 2010). Pulling it in 2005/2008 requires a fairly deep knowledge of your current industry structure, the desired structure and ways to abuse the side effects of various TF teams.
  • Do not create branches inside branches. For example, forking and merging are sometimes recommended as a way to support shared modules or binaries between loosely coupled projects. I don’t think this is very good advice to start with - it is much better for your build system to do its main job properly, rather than forcing your version control system to do what it did not intend to do. In any case, this “sharing” tactic is in terrible conflict with the projects themselves, living inside a wider hierarchy of branches for SCM purposes. If you're not too careful, TFS will happily allow you to create arbitrary, "many times" relationships between version controls. Good luck sorting this out (I once had to do this for a client, not really.)
  • Do not create files with the same relative path in two branches independently; use Merge to fork them, or you'll be chasing namespace conflicts for hours. (n / a in 2010)
  • Do not add redundant files on top of the path where other elements exist. Whether the old elements were renamed / moved or simply deleted, you will encounter interesting tasks at the time of the merger; at a minimum, two checks will be required to complete breeding. (n / a in 2010, although the experience was still somewhat deteriorated, only 1 check is required, the contents of the element are preserved, but the history of names is in this branch and all branches with the stream)
  • Do not use the / force flag unless you know what you are doing. All / forced mergers are usually cherry picks, which leads to very similar risks (the code is lost during the Resolve process, etc. Etc.).
  • Do not use / unseless flags unless you really know what you are doing. You skip deletions - just like shortcuts, except that renames always turn into branches, and not just in case of failure. You do not receive any debit / credit protection at all. And the worst thing of all, you will create new branch relationships. Sometimes. (the user is not informed whether all the target elements are new, old with a new relationship or old with existing relationships).
  • If possible, avoid / discard (and, equivalently, AcceptYours permissions). Discarding some sets of changes just for accepting subsequent ones is another name for cherry picking :)
  • Be careful with your permissions in general. Each of them has unique downward flow effects, in addition to its effect on the merger.
    • AcceptTheirs is a quick and powerful way to get a copy of a merge, as described in the first guide. If you use it in other scenarios, remember that you are not just specifying TFS so that the contents of the file are the same. You say that these two files are fully synchronized with the POV version. To do this, any preliminary changes to the target file that could be merged in the opposite direction will no longer be considered candidates after you check AcceptTheirs.
    • Please note that AcceptMerge (automatic or manual), the final content of which matches the source file, will be considered the AcceptTheirs server. There are no differences in the protocol of the Checkin web service.
    • Using AcceptYours to enable renaming can twist your brain. You will quickly find yourself in a situation where the "same" element has different names in different branches. Assuming that you have a good reason to reject changes in the first place, this phenomenon is essentially unsafe - in fact, you probably need to avoid either interruptions or one-time settings for your files. It just baffles people and is likely to break any automation scenarios you have, which suggests that the tree structures are aligned with branch to branch.
    • AcceptMerge is the default by default. Sometimes this leads to more version conflicts than it seems strictly necessary, but it is the safest choice when true merging is required. (For example, step # 1 of the primary manual is “merge, copy.”) While you are following other recommendations, the number of mergers that require attention from the management should fall - sharply if you come from a workflow that is highly dependent on the choice of cherries.
  • Errors must be associated with the set of changes in which the correction was actually performed. If later you need to drill into downstream branches to see when, where (and possibly how) a fix was distributed, this is purely a version control function. No need to contaminate the work item with extra baggage, much less change the way you merge in principle. In 2005/2008, you can move the merge history using the tf merges command or a third-party interface such as Attrice SideKicks. In 2010, you get great visualizations built into Visual Studio. Instructions and screenshots on MSDN.
+72
Dec 08 '09 at 1:22
source share

I always only merged a number of commits into the integration branch, indicating only the range of change sets that I merged.

Work items that relate to individual work items at the design stage relate to development stages. I don’t think they need to include them in integration or release.

You did not indicate where you record errors / feature requests from clients. If you assign them release branches, you are likely to create other, more detailed work items for the development branch, and when merged you just mark all the problems, bug fixes will be allowed for the branch you merge into.

So, summing up this, I see no reason why not unite with the masses.

+5
Dec 07 '09 at 15:41
source share



All Articles