Rules to Better Branching And Builds

​Since 1990, SSW has supported the developer community by publishing all our best practices and rules for everyone to see. 

If you still need help, visit Application Lifecycle Management and book in a consultant.​​​

Hold on a second! How would you like to view this content?
Just the title! A brief blurb! Gimme everything!
  1. Do you check your Workspaces when defining a new build?

    ​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.
     
      
    Figure: Bad example – Several workspaces from other team projects are included by default
     

      Figure: Good example – Only the relevant workspace has been included in this build definition
  2. Do you know how to name your builds?

    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.
    buildnames.png
    Good Example: We have two continuous delivery​ builds to our staging environment.

  3. Do you know that branches are better than Labels?

    Although labels are useful they can be changed after they have been created with no way to tell that they have been changed.

    Figure: Bad example, labels can be edited after the fact (they are mutable)
    Figure: Good example, branches give absolute certainty of versions (they are immutable)

    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”

  4. Do you know the minimum builds to create for your project?

    ​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. 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?

    Figure: You can control what tests are run and what data is collected while they are running. 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.
     Figure: Bad example, you can't tell what these builds do if they are in a larger list Figure: Good example, you know exactly what project, branch and type of build these are for. 
  5. Do you know when to branch in git?

    ​​
    Note: This rule applies to git. For branching advice in TFVC, see Do you know when to branch in TFVC?

    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.

     

    1) 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.

    2) Create a "feature branch" for every PBI

    When starting a PBI from the taskboard, create a branch from master with a descriptive name for that feature.

    git branch start-stuff
    Figure: Bad example - Branch name is not descriptive
    git branch create-basic-web-application
    Figure: Good Example - Branch name describes the intent of the change

    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 amount of conflicts and churn of unfinished code during development of a feature.  It allows features to be development independently of each other, and reduces the amount of expensive "pull latest from server, and rebuild everything" operations, as well as greatly limiting the impact of commits with unfinished code.

    3) Commit your code to the branch

    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".

    git commit -m "Started report change"
    Figure: Bad Example - Commit message does not describe what was changed
    GoodCommitMessage.png
    Figure: Good Example - Commit message describes exactly what was changed.

    4) Open a pull request

    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.

    It is easy to chalk this step up as busy-work, but it is one of the most valuable parts of the strategy

    5) Deploy

    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 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.

    6) Merge 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. 

    GoodGitHistory.png
    Figure: Good Example - Each change is well described, small and in its own feature branch.

    Once merged, master should immediately and automatically be deployed (in a perfect world, to production) .

  6. Do you know when to branch in TFS (aka TFVC)?

    ​One of the most controversial issues developers discuss is when to create branches and how many you should have.

    Keep things simple:

    1. Have the team develop on the one branch. It is fantastic as there are no more merging hell.
    2. 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.

    Figure: Good Example: Manage deployments to multiple environments, view deployed versions.​

    Why you should avoid branching

    1. Merging is painful, complex and is a time consuming task that does not add value.
    2. Often regressions are introduced as merges are missed and not merged back to trunk
    3. 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
    4. The more you need to create a branch, the harder it is going to be to merge it back into the trunk!
    5. 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
    Figure: Bad Example – Creating a branch per feature leads to lots of merging (Image fromhttp://paulhammant.com/blog/branch_by_abstraction.html )
    Figure: Bad Example – Creating a branch per sprint has everyone working on the same code but requires at least one merge every sprint
    Figure: Good Example: Release Branching - always develop on the trunk, but create a new branch each time you release. 
    This means th​at all developers are continually integrating all their code, branching is rare, but you always have access to your released version in case bug fixes or small mods are required.
    (Image from http://paulhammant.com/blog/branch_by_abstraction.html )

    Further reading:

  7. Do you know when to use an on-premises build server with Visual Studio Online?

    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.

    vso_build.png
    Figure: Good Example - We have the option of an on-premises build controller as well as the Hosted Build controller
  8. Do you swarm to fix the build?

    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:

    1. Get it Green 
    2. 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.

    broken builds.png
    Bad Example: Too many broken builds in a row.


    ​​good builds.png

    Good Example: Broken build was fixed immediately.