Branching in TFS — How Does it Work
TFS — Microsoft Team Foundation Server — helps manage both teams and their code. And over the years, it has evolved. So how does branching in TFS version control work?
Review your TFS branching strategy and find the right one for your team. Then start branching and merging in TFS,
Branching in TFS — How Does it Work
Branching in TFVC uses path-based branches that create a folder structure. When you create a branch, you define a source, usually the main folder, and a target. Then files from the main folder are copied into your branch.
As developers work, they are encouraged to forward integrate (FI). This merges changes from the parent branch — often the main branch — to child branches. Once changes are tested, code can be reverse integrated (RI). This means changes are promoted from child to parent branches.
A directory structure is required to organize and keep track of changes and folders. This structure defines labels for branches based on their purpose: main, development, release. Once defined, it is necessary to communicate it to development and release management teams.
But as your organization and projects grow, this directory structure can get complicated. It can be difficult for everyone to follow. It often requires users to manually find all the branches needed to build and test.
How to View Branching in TFS
Visualization for branching in TFS is available as a graph. It can show you how branches have been built. But it does not indicate the stability of different branches or the intended merge pathways. This is still on developers to figure out.
For example, there is no indication that a particular release branch would be more stable than a development branch. And using the graph, it is unclear what hot fixes need to be applied to a certain release.
Without visual indicators that to show merges, developers do not know what is pending between branches. Limited visibility can cause costly and difficult merge conflicts that soak up time and potentially delay a release.
The right branching strategy helps development teams move fast.
Release Branching in TFS
With TFS, there are several ways that you can handle releases. You can tag/label each release branch or bug fix.
But the relationship between release branches and the release is not always clear. Teams need to create a naming scheme and define a TFS branching strategy to help document the flow of change. This can be done using an external tool, and for some larger teams, may involve complex scripting. If you are maintaining several releases, this can become very difficult, fast.
TFS Branching Strategy
Branching strategies align your development team. They communicate how code should be developed, promoted, and eventually released. It is important to choose a TFS branching strategy — or combination of strategies — that works for your team and project. This can streamline your process and simplify merges.
With every strategy it is important to frequently integrate (FI) changes from the parent branch. Reverse integrate (RI) back to the parent only when the work has met the criteria for your team (build, test, etc.).
The development isolation TFS branching strategy involves one or more development branches. These are kept separate from the main. Each development branch is a complete copy of the main branch. Development branches are built and tested, then code is promoted to the main branch. Releases are shipped using the main branch.
This strategy works on a small scale but is difficult to manage as you grow. If you have a large mainline, it can take a lot of time to merge changes to development branches. Also, teams will likely keep the dev branches around longer. Long-lived branches can be difficult to maintain in TFS due to merge issues.
Feature Isolation/Feature Toggling
A feature isolation TFS branching strategy is similar to development isolation. But instead of having dev branches that live a long time, work is broken up by feature. When a new feature needs to be created, a branch is made. When work is complete, features are merged back into the mainline.
To keep things simple for your team, establish a consistent naming convention. Branches should be self-describing to allow them to be easily identified by your users. But it is important to keep the number of your feature branches to a minimum. This optimizes your storage and decreases hierarchy visualization noise.
Your admins can also implement this strategy using flags and labels. Although this can lower your total number of branches, it also complicates your build pipeline.
The release isolation TFS branching strategy introduces releases branches from the main. This strategy helps teams manage concurrent releases. Instead of releases just being a copy of the main branch, teams create a new branch to support each release. These can be maintained over a longer period of time.
When using this strategy, it is important to never forward integrate (FI) from main. You also want to make sure to lock your release branches and set up permissions. This prevents a developer from accidently modifying a release. If you have any patches or hot fixes, they can be reverse integrated (RI) back to the main branch. You can use this release branching strategy in combination with the other branching strategies.
Branching and Merging in TFS
Although TFVC has added branching functionality over the years, merging remains slow. Like many legacy VCS systems, TFS development and release management models are built by convention. This combined with ineffective labeling can cause delays for teams.
Dealing With Changesets When Merging
It is important to note that when code is checked in for a merge, the changes are stored in a changeset. These changesets provide information on which files were changed, what changes were made, and by whom. When a merge conflict occurs, you can use changesets roll back changes. This can help you diagnose what went wrong and why a build or test failed.
Let’s review some of the common merging scenarios.
Conflicts Ignoring Merge History in TFS
When branching and merging changes from development and main branches, TFS does not also consider prior merges (merge history). For example:
- A new file is created in main.
- File is branched from main (parent) to dev (child).
- Changes were made to the main branch.
- Changes were made to the dev branch.
- Changes are pushed from dev to the main branch with no conflicts.
- More changes are made to dev.
- When the developer goes to merge changes from the main to dev branch, there is a merge conflict.
This conflict occurs because TFS does not always select the right version. Instead it looks for the closest common ancestor (base version), ignoring the merge history. You can see in the example that the main branch does not recognize the initial push from the development branch. It then creates an issue with future merges. This dramatically increases in complexity and in many cases, can cause data loss.
If you have 1,000s of developers working on 1,000s of files, you will have to sort through each of these conflicts. Dealing with these issues delays your team.
Unsupported Indirect Merges
Merging between sibling branches happens in development. This is especially true when people or teams want to collaborate without pushing changes to the mainline first. It is also used to quickly propagate a bug fix between branches.
In TFS, this type of indirect merging is not supported. Attempting a merge between sibling branches will give developers an error. What they need to do is merge with a parent and then merge those changes into another branch. This can take time, especially if there is a conflict. It can introduce changes to the shared branch that aren’t ready for others to use.
You can force a merge using the baseless merge option. But this increases chances of merge conflicts. That is because when you do a baseless merge, you are disregarding the history of either side. These should be avoided at all cost. One way to prevent needing to do an indirect or baseless merge is to have a well-established TFS branching strategy.
Get Built-In Branching & Support For Merging
Even without difficulties branching and merging, TFS slows down as the number of users, repositories, files, branches, and revisions increases. That plus the lack of tooling and infrastructure can add to your system admin time, increasing the total cost of ownership.
Microsoft is working hard to move TFS users to the Azure cloud, and to attract even more developers to their platform through their acquisition of GitHub. However, many companies still need to scale and support growing teams and compressed release cycles. If you have:
- Large numbers of developers.
- Multiple geographic locations.
- Very large files (and a lot of them).
- Automation needs.
Then these solutions might not be the right fit.
Better Branching With Perforce Streams
Perforce Streams — the branching strategy in Helix Core — gives you powerful and flexible model. It ensures that your teams always know where code should flow. And it supports parallel development and concurrent releases.
Teams can spend time dealing with code, instead of needing to remember a naming convention. And admins don’t need to monitor your TFS branching strategy. With Streams, you get support for complex branching for development and releases (no matter your strategy).
Perforce Streams — How Does it Work
When a developer creates a branch, Streams sets up their workspace automatically. It knows what files are available for the branch. Developers can see which ones are being worked on (and by whom). And with Streams, you always know where your code needs to go.
Using the Stream Graph, teams can visualize how code is propagated. They can quickly check to see if they have the most updated version of the mainline or parent branch. Developers do not need to remember to forward integrate and then reverse integrated. Because with Streams, the merge down/copy up principle is built in. It shows guides developers using visual indicators and won’t let bad merges to happen.
And if there is a conflict, Helix Core keeps track of all your changes in a changelist. This happens automatically and intelligently. If a build breaks, you don’t have to go through and cherry pick all the changes people have made to figure out which one(s) broke it.
See for yourself how you can save time branching and merging with Helix Core.