Rules to Better Branching and Builds
When defining a build, you should always check the Workspace tab. Only the workspace relevant to your build should be included.
If you have a number of Team Projects open from the same TFS Project Collection, all of their workspaces will be included by default. You should remove those workspaces that aren’t being used otherwise the build server will get the source for every workspace in this list before starting a build.
You should always follow a naming standard when naming your builds. This helps you identify their purpose at a glance.
The build name should have the following suffixes, depending on their purpose:
- .CI - For continuous integration builds. These are triggered automatically and do not deploy anywhere.
- .CD.[Environment] - For continuous delivery builds. These are triggered automatically and deploy to an environment. You should specify which environment it deploys to as well.
Good Example: We have two continuous delivery builds to our staging environment.
Although labels are useful they can be changed after they have been created with no way to tell that they have been changed.
Fact #1 : Creating a branch of 1GB of source code does not increase the size of your database by 1GB. It just adds a bunch of pointers. Only the differences are actually stored. Fact #2 : When you delete a branch it is not really “deleted”, you are just ending the history. You can undelete at a later time.
Tip : Find deleted items by ticking “Tools | Options | Source Control | Visual Studio Team Foundation Server | Show deleted items in the Source Control Explorer”
When creating projects one of the only ways that you have of proving that it works and is a viable solution is to build it. This is easy when you only have one developer and that developer will be the only one using a solution. But what if you have 2 developers? How do you prove that one developer's code works with the other? The answer is build servers. These build servers take specific code away to another computer and build it there.
You should always have two builds on your team project. These should be setup and tested using an empty solution before you write any code at all.
![Figure: Two builds named in the format [TeamProject].[AreaPath]_[Branch]|CI|Nightly] for every branch](Builds.jpg)
These builds should use the same XAML build workflow; however you may set them up to run a different set of tests depending on the time it takes to run a full build.
- CI - This should run all Unit Tests and all of the automated UI tests. It is run after a successful developer check-in. Note: This build should take no more than 10 minutes to run.
- Nightly - The Nightly build should run all of the Unit Tests, all of the Automated UI tests and all of the Load and Performance tests. The nightly build is time consuming and will run but once a night. Packaging of your Product for testing the next day may be done at this stage as well. Note: This build can take as long as it needs to - of course more than 24 hours is too long.
Reminder: The same build rules apply to 'release' branches as the 'trunk' branch. Review our rule Do You Know When To Branch? for more information on the best branching strategy.
Important: Gate Builds are bad! Some people believe in having a build that stops developers checking in code unless the build succeeds. See our rule on Do You Know That Gated Checkins Mask Dysfunction?Note: We do not run all the tests every time because of the time consuming nature of running some tests, but ALL tests should be run overnight.
Note: If you had a really large project with thousands of tests including long running Load tests you may need to add a Weekly build to the mix.
The best way to handle continuous development and deployment is following GitHub Flow. The basic idea is to always deploy from master , and to create a feature branch for every feature. When the feature is complete, it is merged back to master via a pull request, which provides a trigger for other developers to build.
Using this strategy, master is always production-ready and deployable.
Set up build system to deploy from the master branch
Your build systems should always deploy from master, and should automatically deploy on every commit to master.Since master is always being deployed, it must always be in a deployable state.
1) Create a branch
a) Create a "feature branch" for every PBI
When starting a PBI from the task board, create a branch from master with a descriptive name for that feature.
It is critical that this branch always comes off master, not another feature branch. Master is the only branch that is mandated to be in a deployable state, so any other option is unsafe.
Obviously, we're creating a lot of branches and merging a lot under this strategy - and that's ok. Be sure to keep your PBIs small (as per do you break large tasks into smaller tasks), and you will not have much merge pain.
The benefit of creating feature branches is to reduce the number of conflicts and churn of unfinished code during development of a feature. It allows features to be developed independently of each other and reduces the amount of expensive "pull latest from the server, and rebuild everything" operations, as well as greatly limiting the impact of commits with unfinished code.
b) Code away and complete the PBI
c) Create a commit - it will contain your changed files on your local PC
While working, commit frequently to this branch with nice, descriptive messages. For example, "Added a field to hold the product category to our timesheet read model" and "added a column to the timesheet summary UI for the product category".
d) Push your changes to your remote Feature Branch
2) Open a pull request (to merge from your current branch to the master)
When the change is complete, or when you want feedback on anything, open a pull request to merge the branch back to master . The pull request is more than just a request to merge, it is a request to have someone review the code and architecture, and to discuss any issues. Resolve these issues with more commits in the branch before continuing.
Tip: A best practice is to have another developer review your work and then approve.
It is easy to chalk this step up as busy-work, but it is one of the most valuable parts of the strategy
Deploy the changes to a staging environment. This allows the features to be tested before being merged to master .
Some prefer to move this step to after the merge, especially when using a release management tool like VSTS Release or Octopus Deploy (see Do you use the best deployment tool). If you decide to go this route, remember that master should remain deployable and production ready at all times and that all branches come from master . If skipping this step, ensure that you have CI on your feature branch to ensure that your branch compiles and passes all tests before merging.
3) Merge and Deploy (to master)
Once everyone is happy and everything is tested, complete the pull request, which will merge back to master . Ensure you are not using the "Fast Forward" merge option (git), or details about the branch will be lost - it will appear as though all work was done in master . Being able to see the feature branches in the git log is very useful.
After you completed the pull request, make sure you also delete the branch that you made the pull request of. Deleting your completed branch will not just help yourself in the long run, but also everyone else. Having too many branches especially a stale one will confuse developers on what "may" be in progress, moreover it would cause so much pain to the future developer when they have to do a clean-up and the branch author has left.
Figure: Bad Example - Lots of stale branches that could cause confusion or potentially take a long time to resolve conflicts when merging
Figure: Good Example - Automatically delete the branch after the pull request completion in Azure Devops
Figure: Good Example - Set the whole project to auto-delete branch after merging in GitHub
Once merged, master should immediately and automatically be deployed (in a perfect world, to production).
This rule only applies to TFVC. For git, see here: https://www.ssw.com.au/rules/do-you-know-when-to-branch-in-git
One of the most controversial issues developers discuss is when to create branches and how many you should have.
Keep things simple:
- Have the team develop on the one branch. It is fantastic as there are no more merging hell.
- Have that branch called " master " if using Git and " main " or " trunk " when using TFS or SVN
Beware of smart bloggers giving the wrong advice :-) as many smart people like creating branches e.g. http://blog.hinshelwood.com/archive/2010/04/14/guidance-a-branching-strategy-for-scrum-teams.aspx. Even Martin Fowler says there are a number of issues related to merging that lead us to try and minimise the number of branches that we work with in his article on Feature Branches.
The quintessential scenario you need to support is that emergency "Hey we have a security hole on the site and Hanselman has just tweeted it!"
In that case you need to potentially update all of your branches and perform deployment, which can be quite tiresome.
The better way is to use OctopusDeploy which relives developers from having multiple branches because you only have to worry about building on one branch and deployment can be done automatically to multiple environments. Octopus provides more secure, feature-rich environment which makes it very easy to deploy and promote builds between environments.
Why you should avoid branching
- Merging is painful, complex and is a time consuming task that does not add value.
- Often regressions are introduced as merges are missed and not merged back to trunk
- The longer branches are, the more people that have worked on them... the more unpleasant the merge is going to be. Amount of pain = size of the change * the amount of work on the trunk in that period
- The more you need to create a branch, the harder it is going to be to merge it back into the trunk!
- Branching impedes refactoring. If a am working on a branch and perform sweeping renaming, and a developer working on another branch does the same – merging is nearly impossible. This is very likely to happen on code bases that require tidying when you have developers who believe in improving code as they go (see the Boy Scout Rule)
When it's OK to branch
- For a disposable, investigatory spike
- To perform hotfixes to production environment
If you are using Visual Studio Online, there's an awesome Hosted Build Server option you can use to perform your builds with little to no setup. But if you're working on a project that has continuous integration and a long build time, it's not long before those build minutes start to add up.
To reduce your build costs, you could reduce the number of builds or try to reduce the build time. Continuous integration is very important so you don't want to turn that off, and we encourage checking in early and often. Reducing the build time is a nice idea, but you can't always reduce it enough to make a difference.
For large, expensive projects, the best option is to configure an on-premises build server rather than using hosted builds.
To configure an on-premises build server for Visual Studio Online, check out Anthony Borton's great walkthrough:
Once you have a build server configured, you'll be able to see the build controller as an option when you configure a new build definition.
If you or someone on your team has broken the build, the whole team should swarm to fix the problem immediately.
It is PERFECTLY ok to have the CI build go red, that is what is there for, but when the build goes red the team should go immediately into corrective action mode and make sure the build goes green again.
Two things should be done:
- Get it Green
- Find out WHY it went green locally but red on build server. This may indicate something is brittle in the application structure, and that is the underlying cause – and should of course also be fixed.
Bad Example: Too many broken builds in a row.
Good Example: Broken build was fixed immediately.