Hotfix Process
x.y.z
x = major version number
y = minor version number
z = patch version number
As mentioned on the Release Process page, hotfixes and emergency patches are released by bumping the patch version number.
Fixing Problems¶
Why Hotfixes are Necessary¶
A hotfix refers to a short-term quick fix for a problem with something running in production.
To understand why hotfixes are necessary, consider the following scenario:
suppose you cut a release 1.4.y
, and a group of users adopts that version
and starts using it in production.
Separately, suppose you develop several major features and you cut a new major
release, 2.x
. Going forward, you would prefer if everyone adopted the 2.x
branch, and all future development will focus on 2.x
(there will not be a 1.5
),
but you still have users using 1.4.y
in production.
Hotfix Scenario¶
Suppose we have a tag for v1.4.0, which was cut some time in the past,
and since then we have created a new major version 2.0.0
and its corresponding tag.
main
tag:v2.0.0
|
o--o--o--o--o--o
/ develop
o--o--o--o--o
|
|
tag:v1.4
Now suppose we need to fix something in 1.4.0
(which tag:v1.4
points to). There are two scenarios:
- The fix for 1.4.0 fixes something that no longer applies in 2.0.0 (one-off hotfix)
- The fix for 1.4.0 fixes something that is still in 2.0.0 (upstream hotfix)
Prepare to Apply Hotfix¶
Whichever approach you are going to use, you will need to create a starting branch.
Create a new branch starting at the commit that the v1.4 tag points to.
Here's how to do that:
Start by making sure you have the latest tags:
git fetch --all --tags
Assuming your working directory is clean, you should be able to check out the tag you want to apply the hotfix to:
git checkout tags/v1.4 -b release/v1.4
Now the git diagram looks like this:
release/v1.4
o--o--o--o--o
|
|
tag:v1.4
One-Off Hotfix¶
The following procedure is for a fix to version 1.4.y that does not affect version 2.x.
Step 1: Create Hotfix Branch¶
Starting from branch release/v1.4
, create a new hotfix branch. Here, we call it
hotfix/v1.4/fix-typos
but that naming convention is arbitrary:
git checkout -b hotfix/v1.4/fix-typos
Now the git diagram looks like this:
hotfix/v1.4/fix-typos
release/v1.4
o--o--o--o--o
|
|
tag:v1.4
Step 2: Make Commits to Hotfix Branch¶
Contribute typo fixes to version 1.4.0
with git commit
commands:
hotfix/v1.4/fix-typos
o--o--o
/
/
o--o--o--o--o release/v1.4
|
|
tag:v1.4
This branch should also bump the patch version number using the make rule:
make bump_patch_version
For example, if the original tag v1.4 pointed to the 1.4.0 commit, then the hotfix should bump the patch version to 1.4.1.
(Update the CHANGELOG too.)
Step 3: Merge Hotfix to Release Branch¶
Once all commits have been added to the hotfix and it is ready to merge back into
the release branch, open a pull request to merge hotfix/v1.4/fix-typos
into
release/v1.4
.
Once the PR is opened, reviewed, approved, and merged, the git diagram will look like this:
hotfix/v1.4/fix-typos
o--o--o
/ \
/ \
o--o--o--o--o ----------o
| release/v1.4
|
tag:v1.4
Now, from the release/v1.4
branch, run the release script,
but because this is fixing a version that is no longer the
latest version, we should only create a git tag for the
new release, we should not cut that release to main.
make release_tag
Step 4: Bump Version¶
You are ready to run bump2version to bump the patch version, 1.4.0
to 1.4.1
,
and update the v1.4
git tag to point to the new commit:
make bump_patch_version
(Note: we do not want to cut a release to main, because a newer version has already been cut to main.)
Upstream HotFix¶
Now let's walk through how to deploy a hotfix that affects both 1.4.0 and 2.0.0.
Revisiting the git diagram:
main
tag:v2.0
|
o--o--o
/
o--o--o--o--o
|
|
tag:v1.4
We can start at the common ancestor commit, which in this case is git tag v1.4.
Step 1: Create Hotfix Branch from Common Ancestor¶
We check out the hotfix branch directly from that common ancestor's git tag:
git fetch --all --tags
git checkout tags/v1.4 -b hotfix/fix-typos
Step 2: Make Commits to Hotfix Branch¶
Contribute fixes to the hotfix branch with git commit
commands:
main
tag:v2.0
|
o--o--o
/ hotfix/fix-typos
o--o--o--o--o--------o--o--o
|
|
tag:v1.4
Now we have to merge the hotfix into any older versions that are affected (and their version number bumped), and merge the hotfix into the latest version if it is affected (and its version number bumped). If the latest branch is updated, a new release should also be cut to main.
Step 3: Merge Fixes to Older Version¶
Now we have to merge the hotfix changes into the tagged prior versions, and bump the version number, and if this is the latest branch, cut a new release to main.
Start by fetching all the tags:
git fetch --all --tags
Now check out the tag for the older version, 1.4. Create a new release branch:
git checkout tags/v1.4 -b release/v1.4
git merge --no-ff hotfix/fix-typos
which will result in this git diagram:
main
tag:v2.0
|
o--o--o
/ hotfix/fix-typos
o--o--o--o--o--------o--o--o
|\ \
| \--------------o
| release/v1.4
tag:v1.4
Step 4: Bump Version on Older Version¶
Now run bump2version to bump the patch version, 1.4.0
to 1.4.1
,
and update the v1.4
git tag to point to the new commit:
make bump_patch_version
(Note: we do not want to cut a release to main, because a newer version has already been cut to main.)
This results in:
main
tag:v2.0
|
o--o--o
/ hotfix/fix-typos
o--o--o--o--o--------o--o--o
\ \
\--------------o---o
| release/v1.4
|
|
tag:v1.4
Step 5: Merge Fixes Upstream to Newer Version¶
Similarly, the hotfix can be merged into v2.0.
Start by fetching all the tags:
git fetch --all --tags
Now check out the tag for the newer version, 2.0. Create a new release branch:
git checkout tags/v2.0 -b release/v2.0
git merge --no-ff hotfix/fix-typos
This results in:
main
tag:v2.0
| release/v2.0
o--o--o--------o
/ /
o--o--o--o--o--------o--o--o hotfix/fix-typos
\ \
\--------------o---o
| release/v1.4
|
|
tag:v1.4
Step 6: Bump Version on Upstream¶
Now run bump2version to bump the patch version, 2.0.0
to 2.0.1
,
and update the v2.0
git tag to point to the new commit:
make bump_patch_version
This results in:
tag:v2.0
|
|
| release/v2.0
o--o--o--------o---o
/ /
o--o--o--o--o--------o--o--o hotfix/fix-typos
\ \
\--------------o---o
| release/v1.4
|
|
tag:v1.4
Finally, because this is the latest version, run make release to cut the newest release to the main branch:
make release
This results in the v2.0 tag being cut to main:
main
tag:v2.0
|
|
| release/v2.0
o--o--o--------o---o
/ /
o--o--o--o--o--------o--o--o hotfix/fix-typos
\ \
\--------------o---o
| release/v1.4
|
|
tag:v1.4