Branching Patterns: Navigating the Source Code Maze. Strategies for Streamlined Version Control

Roman Glushach
11 min readJul 21, 2023
Branching Patterns

Version control is a system that records changes to a file or set of files over time. It allows you to keep track of who made what changes, when, and why. It also lets you compare different versions of your code, merge them, or revert to a previous state if needed.

Version control is essential for software development because it enables you to:

  • Collaborate with other developers on the same codebase
  • Experiment with new features or bug fixes without affecting the main code
  • Review and test your code before deploying it to production
  • Maintain a history of your code changes and document them
  • Backup your code and recover from disasters

There are many version control systems available, such as Git, Subversion, Mercurial, CVS.

What is a branching?

Branching is a feature of version control that allows you to create multiple copies of your codebase, each with a different name and purpose. You can think of branches as parallel lines of development that diverge from a common point (usually the main branch).

Branching allows you to:

  • Work on different features or tasks independently without interfering with each other
  • Isolate your code changes from the main branch until they are ready to be merged
  • Test your code in different environments or scenarios before deploying it to production
  • Experiment with new ideas or technologies without risking the stability of the main branch
  • Implement different versions or variants of your product for different customers or markets

Benefits

  • Parallel Development: Branching allows developers to work on different features or tasks simultaneously, without interfering with each other’s work
  • Isolation and Experimentation: Branches provide a safe environment for developers to experiment with new features or changes without affecting the main codebase
  • Bug-Free Code: By maintaining separate branches for bug fixes, developers can quickly address issues and merge the changes back to production without disrupting the development workflow
  • Organized Work: Different types of branches make it easier for developers to organize their work and track progress on specific features or releases
  • History: track the evolution of your project over time, see who made what changes and when, and understand the rationale behind them. You can also identify and fix bugs or issues that may have been introduced by previous changes

Use Cases

Different branching strategies are suitable for various use cases in software development.

Agile Development

Feature branching and GitFlow are often used in agile development environments, allowing for parallel development and easy tracking of feature progress.

Large-Scale Projects

Trunk-Based Development is often used in large-scale projects, where a high degree of coordination and collaboration is required to ensure the codebase remains stable and releasable.

Hotfixes and Bug Fixes

Release branching is useful for addressing critical issues and applying bug fixes to specific versions of the codebase.

Experimental Features

Feature branching and Trunk-Based Development can be used to experiment with new features or changes without affecting the main codebase.

Best practicies

  • Name your branches clearly and consistently: Use descriptive and meaningful names for your branches, such as feature/XYZ or release/1.2.3. Follow a naming convention that everyone agrees on and follows
  • Keep your branches short-lived: Avoid having long-lived branches that diverge too much from the main branch. Merge your branches back to the main branch as soon as possible, preferably after each feature or task is completed. This will reduce the risk of conflicts and keep your code up to date
  • Pull changes from the main branch regularly: Update your branches with the latest changes from the main branch frequently, preferably before starting a new feature or task. This will ensure that your code is compatible with the main branch and prevent conflicts later on
  • Resolve conflicts promptly: If you encounter a conflict when merging your branch to the main branch, resolve it as soon as possible. Use a merge tool or a code editor that can help you compare and merge the conflicting files. Communicate with the other developers who are involved in the conflict and agree on a solution
  • Test your code before merging: Make sure that your code works as expected before merging it to the main branch. Run unit tests, integration tests, code analysis tools, or any other quality checks that you have in place. Fix any bugs or issues that you find before merging
  • Review your code before merging: Get feedback and approval from other developers before merging your code to the main branch. Use a code review tool or a pull request system that can help you share and discuss your code changes. Address any comments or suggestions that you receive before merging
  • Use rebase or squash to keep your branch history clean and linear. This will help you to avoid unnecessary merge commits, conflicts, and complexity in your branch history. You can use commands like git rebase or git merge — squash to rebase or squash your branch onto the main branch before merging it
  • Use tags or labels to mark important points or milestones in your branch history. This will help you to track and reference specific versions or states of your code, such as releases, deployments, tests, etc. You can use commands like git tag or git label to create tags or labels for your branches

Potential Problems and Solutions

  • Merge Conflicts: can occur when two or more developers make changes to the same codebase simultaneously. To avoid conflicts, establish clear guidelines for when to merge and rebase branches, and encourage regular communication and collaboration among team members
  • Long-Lived Branches: can become difficult to manage and merge, leading to delays and conflicts. To avoid this, encourage developers to keep branches small and focused, and regularly merge and integrate changes
  • Lack of Communication: can lead to confusion and conflicts when working with branches. To avoid this, establish clear communication channels and encourage regular updates and status reports
  • Inconsistent Branch Naming: can make it difficult to track and manage branches effectively. To avoid this, establish clear naming conventions and guidelines for branch naming, and ensure that all team members follow them

Gitflow

Gitflow

GitFlow is a branching model that was introduced by Vincent Driessen in his blog post “A successful Git branching model”. It is based on two main branches: master and develop. The master branch contains the stable code that is ready for production. The develop branch contains the latest code that is under development.

In addition to these two main branches, GitFlow uses 4 types of supporting branches:

  • feature: used to develop new features or enhancements for the next release. They are created from the develop branch and merged back into it when they are done
  • release:used to prepare for a new release. They are created from the develop branch and merged into both master and develop when the release is finished
  • hotfix: used to fix urgent bugs or issues in the production code. They are created from the master branch and merged into both master and develop when they are done
  • support: used to maintain older versions of the product that are still supported by the customers. They are created from specific points in the master branch and receive only bug fixes or minor changes

GitFlow is a comprehensive and well-defined branching model that provides clear guidelines for managing complex projects with multiple releases and versions.

However, it also has some drawbacks, such as:

  • It requires a lot of branches and merges, which can be cumbersome and error-prone
  • It introduces a lot of overhead and complexity, which can slow down the development process and reduce agility
  • It assumes a linear and predictable release cycle, which may not suit some projects that need more flexibility or continuous delivery

GitHub Flow

GitHub Flow

GitHub Flow is a branching model that was introduced by Scott Chacon in his blog post “GitHub Flow”. It is based on a single main branch: master. The master branch contains the production-ready code that is always deployable.

In GitHub Flow, every feature or task is developed in a separate branch, which is created from the master branch. The branch name should be descriptive and meaningful, such as the name of the feature, the issue number, or the developer’s name. The branch should be pushed to the remote repository as soon as possible, so that other developers can see it and collaborate on it. The branch should also be kept up to date with the master branch by pulling or rebasing regularly.

When the feature or task is completed, the branch should be reviewed by other developers using a pull request. A pull request is a way of requesting feedback and approval for your code changes from other developers. It also allows you to discuss, comment, and suggest improvements for your code. If the pull request is approved, the branch can be merged into the master branch using a fast-forward merge or a squash merge. If the pull request is rejected, the branch can be modified or closed. After the branch is merged or closed, it should be deleted.

GitHub Flow is a simple and lightweight branching model that provides a fast and agile development process. It also supports continuous integration and continuous delivery, as every code change can be tested and deployed automatically.

However, it also has some drawbacks, such as:

  • It does not support multiple releases or versions of the product, as there is only one main branch
  • It does not provide a clear distinction between development and production code, as they are both in the same branch
  • It relies heavily on pull requests and code reviews, which can be time-consuming and subjective

Trunk-Based Development

Trunk-Based Development

Trunk-Based Development (TBD) is a branching model that was popularized by Martin Fowler in his blog post “Trunk-Based Development”. It is based on a single main branch: trunk. The trunk branch contains the latest code that is under development.

In TBD, every developer works directly on the trunk branch or on short-lived feature branches that are created from the trunk branch. The feature branches are used to develop new features or enhancements that are not ready to be merged into the trunk branch yet. They are usually merged back into the trunk branch within a few days or hours. The trunk branch is always kept in a stable and deployable state by using automated tests and code quality tools.

When the trunk branch is ready for a release, it can be tagged with a version number or branched into a release branch. The release branch contains the code that is ready for production. It can receive bug fixes or minor changes from the trunk branch or from hotfix branches. Hotfix branches are used to fix urgent bugs or issues in the production code. They are created from the release branch and merged back into it when they are done.

TBD is a minimalist and efficient branching model that provides a high level of collaboration and integration among developers. It also supports continuous integration and continuous delivery, as every code change can be tested and deployed frequently.

However, it also has some drawbacks, such as:

  • It requires a high level of discipline and trust among developers, as they are working on the same branch
  • It requires a high level of automation and quality assurance, as every code change can affect the stability of the trunk branch
  • It does not support long-term or parallel development of features or versions, as there is only one main branch

Feature Branching

The idea of feature branch is not new. It dates back to the early days of version control systems, such as CVS and Subversion, where branching and merging were expensive and error-prone operations. Developers used feature branches sparingly, only for large and complex features that required long-term development and isolation from the main codebase.

However, with the advent of distributed version control systems, such as Git and Mercurial, branching and merging became fast and easy. Developers could create and switch between branches locally, without relying on a central server. This enabled a more frequent and fine-grained use of feature branches, where developers could create a branch for every small feature or bug fix they worked on.

The popularity of feature branch also increased with the rise of online platforms for code hosting and collaboration, such as GitHub, GitLab, and Bitbucket. These platforms introduced the concept of pull requests, which are a way to initiate discussions around a branch. Developers can open a pull request to request feedback, code review, or approval from other developers before merging their feature branch into the main codebase. Pull requests also make it easy to track the progress and status of each feature branch.

Feature branching is a branching strategy where you create a new branch for every feature or task you work on. A feature branch is a short-lived branch that contains only the changes related to that feature or task. You can think of it as a sandbox where you can experiment and test your code without affecting the main branch.

The main branch, also called the master branch or the trunk, is the branch that contains the stable and production-ready version of your code. The main branch should always be deployable and free of bugs. You should never commit directly to the main branch, but instead use feature branches to make changes and then merge them back to the main branch when they are ready.

However, feature branch also has some drawbacks that need to be considered:

  • introduces integration issues if developers do not synchronize their branches frequently with the main codebase
  • creates merge conflicts if developers modify the same parts of the code on different branches
  • increases the complexity and overhead of managing multiple branches and pull requests

Release Branching

Release branching is not a new concept. It has been used by many software teams for decades, especially in large and complex projects that require stability and reliability. However, it became more popular and widely adopted with the rise of distributed version control systems (DVCS) like Git in the 2000s. DVCS made branching easier and faster by allowing developers to create and manage branches locally without relying on a central server. This gave developers more flexibility and control over their code changes and enabled them to collaborate more effectively with other developers through pull requests. DVCS also made merging branches simpler and safer by using algorithms that can automatically resolve most conflicts and by providing tools that can help developers review and test their merges before pushing them to the remote repository.

Moreover, DVCS enabled teams to adopt agile methodologies that emphasize frequent delivery of working software and continuous feedback from customers. By using release branching, teams can deliver value to their customers more quickly and regularly while maintaining high quality standards.

Release branching is a type of long-lived branch that contains the code for a specific release of a software product. It is created from the mainline branch, where normal development work happens. It allows for isolated bug fixes and patches to production without affecting the mainline. It is an industry-standard approach recommended in the Continuous Integration book and can be applied to Power BI projects.

However, release branching also has some drawbacks, such as:

  • Increasing the complexity and overhead of managing multiple branches: This requires more coordination and communication among team members and stakeholders
  • Creating potential code divergence between branches: This can lead to merge conflicts, duplication, or inconsistency of code changes
  • Delaying feedback and integration of code changes from different branches: This can reduce visibility and transparency of the development process

Conclusion

Version control systems, such as Git, play a crucial role in enabling Continuous Integration. It is essential to adopt a branching strategy that facilitates frequent code integration while maintaining code stability. Common branching strategies include:
Trunk-based Development: All developers work on a single main branch, committing their changes frequently. This strategy promotes continuous integration and minimizes the risk of integration issues.

Branching are essential tools for software development projects. They allow you to manage your code changes, collaborate with others, and deliver your product effectively.

However, choosing or designing a branching strategy for your project can be challenging, as there are many factors to consider and trade-offs to make.

--

--

Roman Glushach

Senior Software Architect & Engineer Manager at Freelance