Branch Management

Hero image for Branch Management

The team’s methodology is mostly inspired by git-flow, based on separating work by branch types: feature/bug/chore (user story types) and release type.

Formatting

  • Use lowercase and kebab-case for branch names.

    feature/list_job_positions
    Bug/userResetPassword
    
    feature/list-job-positions
    bug/user-reset-password
    
  • Use the forward slash / to separate the branch type from the branch title.

    feature-list-job-positions
    bug_user-reset-password
    
    feature/list-job-positions
    bug/user-reset-password
    

Naming

  • Find a balance between conciseness and descriptiveness for branch titles.

    feature/as-a-user-i-can-logout
    bug/as-an-admin-when-i-select-a-menu-item-i-see-a-highlight
    
    feature/user-logout
    bug/admin-menu-item-highlight
    

    This helps developers distinguish each branch easily.

  • Prefix the branch title with the areas of implementation.

    ui/feature/add-cart-item
    integrate/feature/add-cart-item
    
    feature/ui-add-cart-item
    feature/integrate-add-cart-item
    

    The branch prefix allows immediately recognizing the specific work area. It is specifically beneficial when stories of a single story are divided into multiple implementation parts, and developers need to create separate branches accordingly.

  • Prefix the branch title with the backlog item ID when using project management tools such as Shortcut or JIRA.

    sc-6862/ui/feature/list-job-positions
    939/feature/improve-multiple-dependent-branches-management-guideline
    
    feature/sc-6862-ui-list-job-positions
    feature/939-improve-multiple-dependent-branches-management-guideline
    

    The aforementioned tools require it for their Git integration to function. While other tools, such as Pivotal Tracker, rely on the commit message content to include the backlog item ID. When having both an areas-of-implementation prefix and a backlog item ID prefix in the branch title, the ID prefix must be added before the areas-of-implementation one. Having a standard branch prefix convention will be quite beneficial, especially when DevOps engineers want to set up some triggers for the CI pipeline using the branch title format.

Branch Types

Here is a diagram that represents the standard Gitflow for all branch types, which developers ought to follow:

All Branches Gitflow

Default Branches

  • A repository must have two default branches: main and develop:
    • The main branch is the version in production.
    • The develop branch is the version currently in the staging environment.
  • Both branches must be created when setting up a new code repository:

    git init
    git checkout -b main
    git checkout -b develop
    
  • Committing directly to either the main or develop branches is prohibited. All code must be committed via pull requests.

    Branch protection rules must be set up at the code repository level to prevent direct commits to the main and develop branches (refer to protected branches on GitHub).

Working Branches

  • All feature, bug, and chore branches must be branched from develop. Unless in specific cases, not branching more than one node away from develop avoids complex conflicts and rebasing, which can take hours or days to solve.

  • Once merged, feature, bug, and chore branches must be deleted to keep a sane git tree with only the default and active branches.

No code can be committed without a user story for the tasks. No working branches can be created without a user story. If a user story is not created, the developer must coordinate with the Team Lead and Product Manager before starting any work.

Release Branches

Release branches are created to merge code to the main branch. Working branches must not be merged directly into the main branch.

  • Release branches must be checked out from the develop branch.

  • The name for release branches must contain the corresponding semantic version number.

    release/1.0
    release/v1.0
    
    release/1.0.0
    

Hotfix Branches

Hotfix branches are created to fix bugs in the version currently in the production environment.

  • Hotfix branches must be checked out locally from the main branch (or the current release branch).

  • Correctly applying a hotfix requires to:

    • Open a first pull request to merge the code from the hotfix branch to the main branch (or the current release branch).
    • Open a second pull request to merge the code from the hotfix branch to the develop branch.

Dependency Management

During the development process, when a team of developers works on the same codebase concurrently, it is common to have branches that depend on each other.

There are two common cases:

  • The code changes from a developer have been merged into develop after a working branch was created.
  • Implementing a feature requires the implementation of another feature that is being developed in a separate branch.

In such cases, the required code changes must be brought to the working branch using the rebase or cherry-pick strategy.

While merge can be used, the team discourages it because it creates a merge commit that pollutes the commit history. The merge commit is only necessary when merging a feature, chore, or bug branch into the develop branch. It is unnecessary when bringing the code from one working branch to another.

Rebase Strategy

The preferred strategy to bring the code from one branch to another is to use the rebase command. This command allows developers to move the commits from one branch to another. Technically, it rewrites the commit history of the target branch by adding the commits from the source branch before the commits of the target branches.

Using rebase to get all commits

  • Verify the state of all commits in the source branch before performing any rebase operation to ensure the source branch is functional and buildable. If the source branch is not functional, the rebase operation will result in bringing broken changes to the target branch.

  • Fetch the latest version of the source branch before performing any rebase operation to ensure that the latest code changes are available locally.

    # Given local branch is feature/939-improve-multiple-dependent-branches-management-guideline
    
    git fetch origin develop:develop
    git rebase develop
    
  • Prefer to “clean up” the commit history of the current branch before rebasing it. The common method is to squash the commits of the current branch into fewer commits.

    git rebase -i HEAD~2
    git rebase -i origin/develop
    

    During a rebase, all commits from the source branch are applied individually to each commit of the target branch. If the source branch has ten commits and the target branch has five commits, the rebase will apply the ten commits from the source branch to each of the five commits of the target branch. As a result, many code conflicts might need to be resolved manually. Reducing the number of commits of the current branch will reduce the number of conflicts to resolve, hence resulting in a faster rebase.

    git rebase –onto can alleviate the need to squash the commits of the current branch before rebasing it. This command allows developers to rebase a branch onto another branch while skipping a range of commits.

Cherry Pick Strategy

cherry-pick is used to select one or several commits from one branch (or multiple branches) and apply them to another branch. It is a useful command when not all the commits from a branch are needed in another branch.

Using cherry-pick to get some commits

  • Verify the state of the commits in the source branch before performing any cherry-pick operation to ensure the source commits are functional and buildable. If the latter are not functional, the cherry-pick operation will result in bringing broken changes to the target branch.

  • Fetch the latest version of the source branch before performing any cherry-pick operation to ensure that the latest code changes are available locally.

  • Prefer to cherry-pick a single commit at a time.

    If more individual commits are needed, repeat the cherry-pick command per each commit. In case, the needed commits are in a sequence, cherry-picking a chain of commits is also feasible with a single command (e.g., to get both A and B commits run git cherry-pick A^..B). However, balance the number of commits to cherry-pick at once with the number of conflicts that might need to be resolved manually.