Skip to contents

This document is adapted for The Hubverse from The Carpentries Developer’s Handbook (c) The Carpentries under the CC-BY 4.0 license.

A hotfix is a bug fix for a situation where a bug has been found, but the main branch has new features that are not yet ready to be released. This chapter will be a walkthrough of a scenario with a diagram of the status of the Git repository during each iteration based on the real life process used in carpentries/sandpaper#539 to resolve a bug in link processing.

A process for creating a hotfix release is similar to that of the standard release with the following differences:

standard hotfix
parent branch main <tag>
tag and release after merge before merge
merge conflicts never with DESCRIPTION and NEWS.md

Take for example a situation where you want to introduce two new features into the project, so you create two branches for each of them. You finish the first and merge it into the main branch and you are still working on the second. Your Git graph might look something like this:

gitGraph
    commit id: "abcd"
    commit id: "efgh" tag: "0.14.0"
    branch feature1
    branch feature2
    checkout main
    checkout feature1
    commit id: "ijkl"
    commit id: "mnop"
    checkout main
    merge feature1 id: "gpne"
    checkout feature2
    commit id: "qrst"
    commit id: "uvwx"

Step 1: Create a Fix and Pull Request

Then, you get a report (let’s call it issue number 143) that something is broken and you need to fix it immediately. Normally, to fix bugs, you would check out a new bugfix branch from the main branch. Here’s the catch: if you check out from the main branch you will grab feature1 as well, which is not yet ready for production because you intended feature2 to be released along side. In this case, you need to create a hotfix, and create the branch from the last tag (which in this case is 0.14.0).

IMPORTANT: When you create a hotfix, name the branch <author>/hotfix/<issue>. By using /hotfix/ in the branch name, the GitHub workflows will know to test this package against the released versions from the R-universe.

(main)$ git describe
#| 0.14.0-3-ggpne
(main)$ git switch --detach 0.14.0 # checkout the tag
#| HEAD is now at efgh Merge pull request #140 from hubverse-org/release-0.14.0
((0.14.0))$ git switch -c znk/hotfix/143 # create a new branch
#| switched to new branch 'znk/hotfix/143'
(znk/hotfix/143)$

gitGraph
    commit id: "abcd"
    commit id: "efgh" tag: "0.14.0"
    branch feature1
    branch feature2
    branch znk/hotfix/143
    checkout main
    checkout feature1
    commit id: "ijkl"
    commit id: "mnop"
    checkout main
    merge feature1 id: "gpne"
    checkout feature2
    commit id: "qrst"
    commit id: "uvwx"
    checkout znk/hotfix/143
    commit id: "yzAB"

Once you have made your hotfix (with a test of course, because we always make sure to verify our fixes), then you should push it up and open a pull request:

(znk/hotfix/143)$ git push -u origin znk/hotfix/143

Step 2: Ensure Checks pass and create tag

You should check that the hotfix does not break any existing tests, which are automatically run from the pull request. Once you have confirmed that everything works as expected, the next step is to bump the version and add a tag. This tag will allow you to release the patch version.

(znk/hotfix/143)$ git add DESCRIPTION NEWS.md
(znk/hotfix/143)$ git commit -m 'bump version to 0.14.1'
(znk/hotfix/143)$ git tag -s 0.14.1 -m 'flipped retroencabulator switch option'
(znk/hotfix/143)$ git push
(znk/hotfix/143)$ git push --tags

gitGraph
    commit id: "abcd"
    commit id: "efgh" tag: "0.14.0"
    branch feature1
    branch feature2
    branch znk/hotfix/143
    checkout main
    checkout feature1
    commit id: "ijkl"
    commit id: "mnop"
    checkout main
    merge feature1 id: "gpne"
    checkout feature2
    commit id: "qrst"
    commit id: "uvwx"
    checkout znk/hotfix/143
    commit id: "yzAB"
    commit id: "CDEF" tag: "0.14.1"

**Note the 0.14.1 tag is on the znk/hotfix/143 branch at the bottom.

At this point, the checks will not run on the pull request because there will be a conflict in the DESCRIPTION and NEWS.md files. This is okay. All you did was update the version numbers and add NEWS. Do not merge at this point. The next step is to release the patch.

Step 3: Release the Patch

You will release the patch using the same method as described in the releases chapter. You can either release on GitHub directly or via the GitHub CLI. Importantly, when you create the release, you should create the release from the new tag. This can be done via the GitHub interface or using GitHub’s CLI tool.

(znk/hotfix/143)$ gh release create 0.14.1

Step 4: Resolve Conflicts and Merge

Now that you’ve created the release, you should resolve the conflicts in the DESCRIPTION and NEWS files and then merge it back into main (note: this will create two merge commits, but I’m only showing one in the diagram to make it cleaner):

gitGraph
    commit id: "abcd"
    commit id: "efgh" tag: "0.14.0"
    branch feature1
    branch feature2
    branch znk/hotfix/143
    checkout main
    checkout feature1
    commit id: "ijkl"
    commit id: "mnop"
    checkout main
    merge feature1 id: "gpne"
    checkout feature2
    commit id: "qrst"
    commit id: "uvwx"
    checkout znk/hotfix/143
    commit id: "yzAB"
    commit id: "CDEF" tag: "0.14.1"
    checkout main
    merge znk/hotfix/143 id: "DeFn"

Now you will have the patch in place for the released version and the devel version of this hubverse package, which means that you can continue to develop as normal and merge the next feature when you are ready:

gitGraph
    commit id: "abcd"
    commit id: "efgh" tag: "0.14.0"
    branch feature1
    branch feature2
    branch znk/hotfix/143
    checkout main
    checkout feature1
    commit id: "ijkl"
    commit id: "mnop"
    checkout main
    merge feature1 id: "gpne"
    checkout feature2
    commit id: "qrst"
    commit id: "uvwx"
    checkout znk/hotfix/143
    commit id: "yzAB"
    commit id: "CDEF" tag: "0.14.1"
    checkout main
    merge znk/hotfix/143 id: "DeFn"
    checkout feature2
    commit id: "GHIJ"
    commit id: "KLMN"
    checkout main
    merge feature2 id: "FnNL"