Skip to main content

Git branching strategy

ยท 5 min read

I'm preparing a set of materials for a batch of interns whom I will be mentoring for a software development project.

One of the things that they will be doing is to check out an existing codebase to work on. To do that, they need to know Git.

I'm quite certain that the basics of checking in and out code is no problem for them if they have any Github profiles. However, every organization has its own conventions and requirements when it comes to maintenance of their codebases. This post documents my preferences in code maintenance.

Branching strategyโ€‹

When taking on a new codebase, one of the first things to understand is the branching strategy used by the organization. A branching strategy isn't a Git command or function. Rather it is a set of conventions that determine the approach to handle code changes in terms of code releases, bug fixes and new feature development. The things to consider are the convention for creating and naming of new branches, and the guidelines for when and how to merge changes.

There are several popular ones out there:

One factor affecting the choice of strategy is the size of the team. The size of the team has a direct (but not necessarily proportional) bearing on the number of concurrent branches. It is important to be judicious about selecting the suitable strategy. Each strategy yields different benefits but also introduces additional overhead.

A strategy perfect for a team of hundreds is likely to be too onerous for a team of three.

Some of the strategies above are also outdated in the sense that they do not lend well to the modern strategies of continous integration/continuous deployment (CI/CD).

For a small team of less than five, here are my heuristics (Maybe I should call it SimpleFlow ๐Ÿค”):

  • A production branch should be branched off the main (or master) branch.
  • All releases are made on the production branch.
  • Each release should be accompanied by a tag.
  • This implies that the main branch contains the latest, tested changes.
  • Feature development should take place on branches based off the main branch - these are called feature branches.
  • Feature branches should rebase from the main branch frequently.
  • Feature branch should be merged back into the main branch when development is done.
  • Hotfixes should only be made on branches based off the production branch and merged back into production for release.

By keeping all releases on the production branch only, any CI/CD pipeline can be honoured during deployment.

Exampleโ€‹

Here is an example scenario:

Say Alice is tasked to create a new feature for users to select one of a few preset avatars. She checks out the codebase which defaults to the main branch.

$ git checkout git@github.com:coy-project
$ cd coy-project

She then creates a new branch preset-avatar.

$ git checkout -b preset-avatar

She starts work in this branch.

Halfway through her work, she receives instructions to investigate a reported bug in the production system. She stashes any outstanding work in her branch before switching to the production branch to start investigation work. She creates a new branch hotfix-broken-image to start her code changes. (Before creating the new branch, she should make sure to have the latest commits from production as well.)

# In `preset-avatar` branch.
$ git stash # Put her current work away.
$ git checkout production
$ git pull
$ git checkout -b hotfix-broken-image

She makes the necessary code changes to fix the bug. Then she commits the code to the hotfix branch. Before she makes a pull request (PR) to the production branch, she pulls in the changes one last time. There should not be any more changes to production in this scenario, but edge cases can occur.

$ git commit -m "Fixed broken link to image."
$ git checkout production
$ git pull
$ git checkout hotfix-broken-image
$ git rebase production # Only if there are new changes from `git pull`

The project lead will review the changes. Notice there isn't a command for PRs. PRs are artefacts of the centralised service (i.e. the likes of Github and Gitlab) that provides the centralised Git service - they're not part of the core Git functionality.

After the changes are approved, she will merge the changes into the production branch. In some cases, changes to the production branch are restricted to project leads, so only the project leads can merge the pull request.

$ git checkout production
$ git merge hotfix-broken-image

Regardless of who merges the hotfix into the production branch, Alice goes back to continue to her work on the preset-avatar branch by restoring the changes that she had stashed away earlier.

$ git checkout preset-avatar
$ git stash pop # Restore the work she previously put away.

From this point on, she continues her work.

Identityโ€‹

One other thing that I require collborators to do is to set the name and email of the Git identity that is registered in the Git history.

$ git config user.name "<Your name here>"
$ git config user.email <your@email.com>

This is so that the Git history reflects clearly who made which commits.

I want to avoid entries that look like this when I run git log:

commit 012bf3d06e6f707a23b1786c9bd94f59f851d576
Author: juju <ilovejuju@MacBook-Air.local>
Date: Thu Jul 7 08:48:16 2022 +0800

made code changes

The name and email should be the formal identity registered with the company.

Conclusionโ€‹

This article covers the high-level, strategic approach that I've used for small projects.

The next few articles will cover the more strategic, tactical uses of Git.