Branching
Naming Convention
To keep branches organized we adhere to a naming convention for branches.
This naming convention allows us to easily identify the type of work being done on a branch and will assist in identifying and tracking down stale branches.
Branches for a specific Jira issue
In order to link the work on a branch to our Jira issues, the branch name should be made up of three parts, separated by a slash:
- The team name or abbreviation (e.g.
vault
), and - The Jira issue key (e.g.
pm-1234
) - A short description of the work being done (e.g.
update-csp-hashes
)
In this example, the full branch name would be vault/pm-1234/update-csp-hashes
.
- Use only lower case letters in branch names.
- Separate words with
-
and branch name sections with/
. Only use these characters for word or section separation. - Limit work description section to ~50 characters. Overall branch name should be a maximum of ~80 characters.
- Team names must be consistent. Either always abbreviate or do not abbreviate.
If you are breaking down your changes incrementally, you may find that you need multiple branches to implement a single story. In that case, you can either reference the appropriate subtask key in your branch name or include the story key for all branches, depending on whether you are using subtask-level work breakdown.
Branches for multiple Jira issues
If the branch will contain work from multiple Jira issues (most likely due to it being a
long-lived feature branch), the name should be a descriptive name of
the feature, separated by dashes (e.g. my-long-lived-feature
). Consider brevity when possible, as
our QA team may need to use this branch name when performing QA testing on the feature.
Branching for Development
Which Branching Model to Choose?
The main point of consideration in choosing a branching model is whether the changes can be
introduced directly into main
with every pull request or whether they need to be merged into a
long-lived feature branch for QA. As such, it should be planned in advance when beginning work on a
new set of Jira stories or tasks, and it requires coordination across the entire team - Development,
QA, and Product.
Choose branching and merging into main
if the feature will:
- Require a single pull request to produce a testable, releasable change, with QA taking place on the PR branch, or
- Allow multiple incremental pull requests with the changes encapsulated behind a feature flag,
with QA taking place in
main
.
Choose branching and merging into a long-lived feature branch if the feature will:
- Require multiple pull requests to produce a testable, releasable change, and
- It is not possible to put the changes behind a feature flag
If in doubt, lean toward creating branches directly off of main
for incremental body of work, as
there is overhead built in to the long-lived feature branch.
Structuring branches to support incremental work
Regardless of whether we are merging into main
or a long-lived feature branch, it is important
that each engineer structure their branches to support small, reviewable pull requests. When taking
on a new story or task, and throughout the development process, the engineer should consider how the
work could be broken apart and incrementally introduced for review and merge.
It can be helpful to think of this exercise in terms of two dimensions:
"Horizontal" separation
- The scope of the delivered work remains the same, but we can separate the delivery of the work into smaller PRs.
- We can think of our branches as building blocks that are part of the final, fully constructed feature, with an eye toward making the resulting pull requests concise, well-defined and easily reviewable.
- It is accepted and expected that incomplete code will be merged -- either to
main
behind a feature flag or into the long-lived feature branch. - Examples of this include:
- Introducing supporting services prior to UI development.
- Introducing changes that require feedback from other teams separately.
"Vertical" separation
- The scope of the delivered work can be refined and broken out into multiple different Stories or Tasks.
- Examples of this include:
- Introducing changes to one component or page independently others.
- Introducing changes on a client-by-client basis.
Additional considerations for long-lived feature branches
This section ony applies if a long-lived feature branch is necessary, which we discourage.
A long-lived feature branch is necessary when the body of work to produce the smallest independent testable, releasable change is too large to be encapsulated in a single PR, or it requires the contribution of multiple developers, and it cannot be encapsulated behind a feature flag.
The long-lived feature branch is merely a collection point for work that cannot be merged to main
independently. The developer should still use
branches for small, incremental changes, but
they will target the long-lived feature branch instead of main
.
As a result, the long-lived feature branch should only consist of:
- PRs for approved changes, and
- Merge commits from
main
.
Any other commits directly to the long-lived feature branch will complicate the eventual review of
the final PR into main
and should be avoided.
The review of a long-lived feature branch should simply be a verification of each PR that has been
The final review can be performed using GitHub's UI, by opening the Pull Request and clicking on the
Commits
tab. Each commit can then be checked individually.
- Verify the commit has an existing review by following the pull request link and verifying the
commit SHA hash matches. Look for
Author merged commit {hash} into branch
. - If not perform a regular code review of the commit.
Merge commits should be reviewed as well, the GitHub UI will automatically simplify the merge commit
and only show the changes made. If reviewing from the command line or through a different tool,
please use the command git show <hash>
. For some background and more information please read
How to review a merge commit.
Branching for Release
On the first business day after the Development Complete date for a given release, an rc
branch is
created off of main
. This is a snapshot of the ongoing work in main
that will represent the code
released in the upcoming version.
The rc
branch is used for regression testing. It is then used as the source for the production
release and deployment of each of our deployed entities. When each release is made, a tag of the
format vYYYY.MM.#-{component}
is created. This can be used to hotfix this release at a later
point.
When the release is complete, the rc
branch is deleted.
Hotfix Releases
For a hotfix release, a hotfix branch is created off of the release tag for the release upon which
the hotfix should be applied. The branch naming depends upon the repository. For all repositories
except clients
, the branch name is hotfix-rc
. However, as we can release individual clients
separately, each client in the clients
repo has their own named hotfix branch:
- Web:
hofix-rc-web
- Desktop:
hotfix-rc-desktop
- Browser:
hotfix-rc-browser
- CLI:
hotfix-rc-cli
Once the hotfix branch has been created, the individual commits in main
are cherry-picked into the
hotfix branches. For a client fix, this may require cherry-picking to multiple hotfix branches.
Once the hotfix has been deployed, the hotfix branches are deleted.
For hotfixes, we do not perform QA testing on the feature branch prior to merging into main
. This
is an acknowledged risk that we have incurred in order to speed up the hotfix process and to avoid
having to switch all of our QA testing environments from referencing our hotfix branches.
Instead, hotfixed changes are merged into into main
as soon as the PR is approved and then
cherry-picked to the appropriate hotfix branch(es). They are then tested on the hotfix branch.