In early 2006, we had a difficult bridge to cross as we were about to enter the Construction phase of our current project. Having 35+ developers building interdependent functional areas of the application, we needed to ensure the autonomy of each functional area, whilst maintaining linkage between shared components. Thus, having used branches in the past (quite successfully with Subversion, might I add,) we decided to leverage TFS branches to provide support for our concurrent development efforts.
While quite sound in theory, this has proven to be quite challenging in practice. We've faced several issues, most troubling of which is error TF14087:
TF14087: Cannot undelete '$/Itd/Implementation/R2/Bvi/Framework/Security/Authorization/Principal.cs' because not all of the deletion is being undeleted.
After some research into this error, I came across this excellent explanation of what's going on. Furthermore, we found that the reason for this error occurring in our structure is due to file renaming in the trunk and branches. Thus, as the aforementioned blog post outlines, TFS cannot perform the merge as the linkage between the file is not correctly synchronized (TFS is looking to merge a "deleted" file, although it's really been renamed.)
Furthermore, we also faced issues in that some developers "merged" their branch by copying files locally in their workspace and added them to Source Control as new items. This completely breaks the linkage between the trunk and branches, which was a big headache when trying to perform the merge.
In the end, we spent more than 4 hours manually merging our two active branches – what a pain! Even though there are some workarounds posted out there (here is a fair approach,) we ended up performing the merge manually due to the fact that some defects had been fixed in one branch while other defects in the next branch. Thus, the only way to effectively manage said changes was to manually merge.
Although I'm now a little jaded with TFS Branching, I would recommend the following guidelines if you choose to use this functionality to manage concurrent development activities:
- Merge often – this is a big one, since many of our issues would have been resolved if this rule was followed by our team.
- Rename in trunk, then move to branches – we found that whenever a rename was required, performing this activity in the trunk allowed us to propagate changes to the desired branch without merge errors
- Document merge guidelines – in our situation, we have 35+ developers offshore with some architecture and development oversight resources onshore. Although some resources had used branches before, many were unfamiliar with the process, resulting in the merge-via-copy-and-paste snafu. Thus, clearly documenting the process could have saved us the headaches we've had.
- Keep shared components in single branch – we found that fewer conflicts existed in shared components. Thus, keeping these items in a single branch reduces the margin for error in merging.
In addition to these tips, it is always a good idea to effectively communicate major changes to the code base between the development teams. We're currently implementing a weekly meeting between team leads to discuss the same, and it's looking bright.
The logic and reason behind error message TF14087 (mentioned earlier)