Code Merging & Branch Management

62 team-code-merging-branch

Branching and Merging strategies are a critical component in Continuous Delivery of stable software. Frequent, on demand releases require careful attention to maintaining both a highly stable releasable code base as well
as a disciplined approach to feature development and peer review process in ongoing development sandboxes.

Explore More.

Related Mindset:

Continuous Delivery

Segment:

Team

Inputs:

Story development within branches in version control

Outputs:

A merged and integrated code base which can support development, staging, and production

In order to support both Continuous Delivery and ongoing feature development, a more robust branching and merging strategy than traditionally seen in source control systems such as SVN or CVS must be employed.

In this document, we will outline a branching and merging strategy built atop Git for source control, with specific attention paid towards the goals of quality, releasability and ease of development.

While there are many version control solutions available, Git has solidified its place as a leader both in open source development as well as the enterprise through solutions such as GitHub, Bitbucket, and GitLab. Git’s support for lightweight branches and its distributed approach allows for workflows that simply could not be supported in previous generation version control solutions.

Branching Strategy

This branching strategy is an enhancement of GitFlow which was initially documented by Vincent Driessen at nvie. It is a strategy for Git to support simultaneous feature development, bug fix development and release management in large codebases shared by multiple developers. Prior to the adoption of Git, the branching model utilized in GitfFlow was not possible because it relied on the ability to merge between branches at any time. For instance, if a bug is found during regression, it can be fixed and merged into the Release, and then merged into Work Branches with little concern of conflicts.

Let’s take a look at the standard GitFlow Branching Model and process.

gitflow-branching-model-1

In this model, there are two main branches, Master and Develop, which constitute the main trunk of the repository. The Develop Branch is for ongoing, active development while the Master is for released code only. The Master Branch will in fact contain very few commits, which should only contain tagged, released code. That same code will also be merged to Develop to keep it up to date with Master. In order to work, developers will create branches from Develop or Release, depending on if they are working on a new Feature or a Release Bug.

Features are implemented through User Stories, and GitFlow advocates creating a Work Branch for every single User Story. It is recommended that the ticket ID is used as the prefix for the branch name with a descriptive title for the work to be done. For example, for a User Story with the ID of PK-427 that details the creation of a new user account form, the developer would create a branch from Develop called ‘PK-427-user-account-form.’ As work proceeds, the developer will commit often to their Work Branch, and once complete and approved, the branch is merged back to Develop.

Merging & Pull Requests

While GitFlow does not dictate a specific strategy for merging Work Branches, we recommend using a Pull Request workflow. Instead of allowing developers to directly merge the code in their completed Work Branch into Develop, they create a Pull Request which initiates a Code Review process for other developers to review the work completed. One or more developers will review the new code in its entirety, leaving comments and suggestions for improvements, changes, refactoring, or code cleanup. Once the review is complete and all updates have been committed, the Reviewer will accept the Pull Request, which merges the code back into the Develop Branch.

It is important to understand that no code is ever merged without the Pull Request process, and the developer who opened the Pull Request will never merge their own code. The Pull Request and Code Review process is meant to encourage collaboration and knowledge share, which we have consistently seen lead to a more stable, higher quality code base.

Releasing Code

When it’s time to release the system, a new Release Branch is created from Develop, and the Regression process begins. Developers will create new branches from Release for every defect found. Once a defect is fixed, it will follow the Pull Request process to merge the fix branch to Release. Once the Release Branch has been validated by both QA and business, it is tagged and merged to both Master and Develop.

In this manner, Master will contain only the released, tagged code, and Develop will always be kept up to date with the Master. At any time, Developers can merge Develop into their own Work Branches in order to keep them up to date.

Continuous Delivery & GitFlow

GitFlow, enhanced with Pull Requests and Code Reviews is increasingly popular in the software industry, but falls short in one key area. Every time a release is prepared, it is created from the active Develop Branch, which means all features that have been completed and merged and must be accepted in order to release. This often makes it difficult to plan for a release, as Business must find the optimum time when all approved features are complete. Regression cycles are also often lengthy as QA needs to validate all features delivered to date at once. This is often the first time multiple features have been heavily tested together, and naturally a number of bugs will be discovered throughout the process.

In order to support on demand, Continuous Delivery, we must enhance this process in order to satisfy the following requirements:

  • All Features must be code complete, bug free and approved by Business before being merged with other Features.
  • Business must be able to approve or disapprove any completed Features prior to creating a Release Branch.
  • Regression and testing time must be minimized as much as possible, in order to ensure fast release cycles.
  • The Release Branch must be kept as stable and bug free as possible, so it can be released at any time.

Let’s take a look at how we can modify the GitFlow Branching Strategy to satisfy some of these goals. The largest issue in GitFlow that keeps it from satisfying the above requirements is the Develop Branch. Traditionally, as developers complete User Stories for different Features, they merge the Work Branches back into Develop and move on to a new story. The problem is that Develop continues to gain code for Features that are not complete. Some User Stories are finished and merged, but others are still waiting to be started. When multiple Features are being developed at once, this problem compounds. We must wait for all User Stories and Features in development to be completed and merged in order to begin the Release process. We need a way to develop each Feature in isolation so that it is safe to complete individual User Stories without compromising the common code base.

As you see outlined in the diagram below, we have gotten rid of the Develop Branch entirely, and replaced it with a number of Feature Branches to develop in isolation.

gitflow-branching-model-2

Every time a Feature is started, the latest code in Master is used as a branch point for the new Feature. Starting from Master ensures that the Feature being developed will have no dependencies on unreleased code. As developers work on the User Stories for a specific Feature, they create Work Branches, as before, but this time from a specific Feature Branch. Once all the User Stories are complete for the Feature, it can be reviewed by Business and QA on it’s own branch. If any bugs are found when reviewing the Feature, they will be fixed and merged back into the Feature Branch before being accepted for Release.

By isolating Features this way, we ensure that no code is merged into a central location until it is 100% complete. We’ve also created a process for approval, as Business can review builds of a Feature Branch to ensure they meet the success criteria for that Feature. Any defects, missed Acceptance Criteria, or changes based on Business feedback can be fixed prior to approval. With proper devops in place, we can also provide QA with the ability to build and test each Feature Branch, shifting much of the testing process from the Regression to Development, ensuring the quality of delivered code, and significantly reducing the Regression Cycle during release.

We have also allowed for more flexibility in the release process, as we do not need to wait for any Feature to be finished in order to create a Release Branch. If a Feature is complete and approved, it can be merged to Release. If not, it simply waits for the next Release. This requires Business to shift mindsets into a Continuous Release Process, where as they always have a stable Release Branch ready, and can choose what Features they want to include based on completion, stability, and if the Feature satisfies the business ask for which it was designed.

Common Pitfalls

The major goals of this strategy are the support of Continuous Delivery in conjunction with Feature Development, but often these two concepts are at odds with one another.

Common pitfalls to avoid are:

  • Unstable Release Branch: The most important factor in supporting Continuous Delivery is the stability of the Release Branch. Merging code that has not been fully vetted through the Peer Review process, and not fully tested by QA will have a negative impact on the stability of the Release Branch. The closer to bug free any code entering the Release Branch, the shorter regression cycles will be for each release. The goal is to maintain a Release Branch that is always considered releasable.
  • Long running Feature Branches: As development on a specific Feature continues, it is natural that the Branch created for it will diverge from the current Release Branch. The longer development proceeds, the greater the potential for conflict when merging the Feature when it is accepted. It is critical to keep Feature Branches up to date with the latest changes to Release, but it is also critical to keep the scope of Feature Branches small enough that they can be delivered frequently and the potential for conflict can be minimized.
  • Epic Branches: This strategy relies on the ability to define Features that are very loosely coupled with other Features. The more self contained and simple a Feature is, the faster it can be developed and deployed. Unfortunately, this is often not feasible, and multiple Features require each other, not only in order to be released, but to be developed. In order to support the development of Features that are inherently dependent, it is common to create a shared Epic Branch where the User Stories for multiple Features can be delivered and tested together. There are many times where this strategy is necessary, but the Epic Branch shares all the pitfalls of the Develop Branch described earlier. The Epic must wait for ALL User Stories to be completed, QA must test and approve the entire Epic Branch, and Business must approve all Features contained within it.

Tools

The strategies outlined in this article revolve around source control and supporting tools for managing repositories as well as the peer review process.

  • Git Cloud Version Control Services - Although Git is by nature a non-centralized source control system, it is extremely common to use a single origin repository as a central hub for developers to push completed features to. Not only do Git services provide centralized, cloud-hosted repositories for this purpose, but also provide excellent tools for pull requests and peer reviews.
  • SourceTree: Although command-line usage of Git is often the most flexible, a visual tool for repository and branch management is highly recommended. SourceTree simplifies many tasks in Git, and offers a workflow that fits well within the patterns described in this article.