GitHotfix Workflow

Hotfix Workflow

A hotfix is an urgent fix applied directly to production code, bypassing the normal development cycle. The word "hotfix" implies urgency: something is broken in production right now and users are affected. A payment processor is returning errors, a security vulnerability has been discovered, or a data-loss bug slipped through. Normal feature-branch process is too slow — you need a way to get a fix into production within minutes or hours, not days.

This guide covers hotfix procedures for both GitHub Flow and Gitflow, with full command walkthroughs, version bumping, tagging, team communication, and post-fix monitoring.

What Makes a Hotfix Different

Characteristic

Normal feature branch

Hotfix branch

Source branch

main or develop

main (the tag in production)

Target branch(es)

main

main AND develop (Gitflow) / main (GitHub Flow)

Review process

Normal review cycle

Expedited — 1 approval, immediate merge

CI requirements

All checks pass

All checks pass (never skip)

Urgency

Low–medium

High — production is impacted

Scope

Can be large

Minimal — one bug, no refactoring

Version bump

Minor or patch on next release

Immediate patch version bump

Warning
Never skip tests or CI checks for a hotfix, no matter the urgency. A broken hotfix is worse than the original bug — it adds another outage on top. If your CI pipeline is too slow for emergencies, the right fix is to speed up CI, not to bypass it.
GitHub Flow Hotfix

GitHub Flow has no develop branch, so a hotfix is just a short-lived branch from main with an expedited review.

1. Ensure main reflects what is in production

Bash
git checkout main
git pull origin main
# From github.com:org/project
#  * branch            main -> FETCH_HEAD

2. Create a hotfix branch from main

Bash
git checkout -b hotfix/payment-null-pointer
# Switched to a new branch 'hotfix/payment-null-pointer'

3. Make the minimal fix

Bash
# Edit only the affected file(s)
# src/services/payment.ts — add null check before processing
git add src/services/payment.ts
git commit -m "fix(payment): add null check before charge processing

Fixes a NullPointerException when the customer object is missing
the billing_address field. Added optional chaining and a fallback
to the account address.

Fixes #501"

4. Bump the patch version

Bash
# package.json: 2.4.1 -> 2.4.2
npm version patch --no-git-tag-version
# v2.4.2

git add package.json package-lock.json
git commit -m "chore(release): bump version to 2.4.2"

5. Push and open an expedited PR

Bash
git push origin hotfix/payment-null-pointer
# remote: Create a pull request:
# remote:   https://github.com/org/project/pull/new/hotfix/payment-null-pointer

Ping reviewers directly in Slack/Teams. Do not wait for the normal review cycle. One approval is sufficient for a hotfix.

6. After merge — tag the release

Bash
git checkout main
git pull origin main

git tag -a v2.4.2 -m "Hotfix v2.4.2

- fix(payment): add null check before charge processing
  Fixes NullPointerException when billing_address is missing (#501)"

git push origin v2.4.2

7. Deploy and clean up

Bash
# Trigger your deployment pipeline (CI/CD will pick up the tag)
# OR deploy manually:
git push origin main   # if your CD watches main

# Delete the hotfix branch
git branch -d hotfix/payment-null-pointer
git push origin --delete hotfix/payment-null-pointer
Gitflow Hotfix Process

Gitflow has both a main branch (production) and a develop branch (integration). A hotfix must be applied to both so that the fix is not lost in the next release cycle.

1. Branch from main (not develop)

Bash
git checkout main
git pull origin main
git checkout -b hotfix/2.4.2
# Switched to a new branch 'hotfix/2.4.2'

# Note: branch from the production tag if main has moved since deployment
# git checkout -b hotfix/2.4.2 v2.4.1

2. Bump version and make the fix

Bash
# Bump version in package.json to 2.4.2
npm version patch --no-git-tag-version
git add package.json package-lock.json
git commit -m "chore(release): bump version to 2.4.2"

# Apply the fix
git add src/services/payment.ts
git commit -m "fix(payment): add null check before charge processing"

3. Merge into main and tag

Bash
git checkout main
git merge --no-ff hotfix/2.4.2 -m "Merge hotfix/2.4.2 into main"
git tag -a v2.4.2 -m "Hotfix v2.4.2: payment null pointer fix"
git push origin main --follow-tags

4. Merge into develop so fix is not lost

Bash
git checkout develop
git pull origin develop
git merge --no-ff hotfix/2.4.2 -m "Merge hotfix/2.4.2 into develop"
git push origin develop
Warning
In Gitflow, **always** merge a hotfix branch into both `main` and `develop`. If you only merge into `main`, the next release from `develop` will reintroduce the bug.

5. Delete the hotfix branch

Bash
git branch -d hotfix/2.4.2
git push origin --delete hotfix/2.4.2
Semantic Version Bumping for Hotfixes

Hotfixes always increment the patch version — the third number in MAJOR.MINOR.PATCH:

Version before

Type of change

Version after

2.4.1

Hotfix (bug fix only)

2.4.2

2.4.1

New feature (not a hotfix)

2.5.0

2.4.1

Breaking API change (not a hotfix)

3.0.0

Bump version in common project types

Bash
# Node.js / package.json
npm version patch --no-git-tag-version
# Output: v2.4.2

# Python / pyproject.toml (using bump2version)
bump2version patch
# Edits pyproject.toml: version = "2.4.2"

# Go / manually edit version file
# sed -i 's/Version = "2.4.1"/Version = "2.4.2"/' version.go

# Manual (any project)
# Edit the version field in your config file, then:
git add .
git commit -m "chore(release): bump version to 2.4.2"
Tagging the Hotfix Release

Create an annotated tag with release notes

Bash
git tag -a v2.4.2 -m "Hotfix v2.4.2

Changes:
- fix(payment): add null check before charge processing (#501)

Impact:
- Fixes NullPointerException causing 5xx errors on checkout page
- No database migrations required
- Safe to deploy with zero downtime"

# Push the tag
git push origin v2.4.2

# Verify the tag was pushed
git ls-remote --tags origin
# refs/tags/v2.4.2   a3f9c2145b8d...
Tip
Use `git tag -a` (annotated) rather than `git tag` (lightweight) for releases. Annotated tags store the tagger name, email, date, and message — essential audit trail for production releases.

Create a GitHub Release from the tag (using gh CLI)

Bash
gh release create v2.4.2 \
  --title "v2.4.2 — Payment hotfix" \
  --notes "## Hotfix

### Bug Fixes
- **payment**: Add null check before charge processing (#501)

### Deployment notes
No migrations required. Rollback is safe."
Communicating the Hotfix to the Team

A hotfix affects everyone. Communication should happen at three points: when you start, when you deploy, and after you verify.

When you start the hotfix:

Slack message: hotfix started

Text
🚨 HOTFIX IN PROGRESS 🚨

Issue: NullPointerException on /checkout causing 5xx errors (issue #501)
Impact: ~12% of checkout attempts failing since 14:32 UTC
Branch: hotfix/payment-null-pointer
PR: https://github.com/org/project/pull/502
ETA: ~30 minutes to deploy

@reviewer1 @reviewer2 — expedited review needed ASAP

When you deploy:

Slack message: hotfix deployed

Text
✅ HOTFIX DEPLOYED

v2.4.2 is now live on production.
Commit: a3f9c21
Deployed at: 15:04 UTC

Monitoring error rates now. Will confirm fix in 15 minutes.
Post-Hotfix: Verify and Monitor
  1. Immediately after deploy: check error monitoring (Sentry, Datadog, Rollbar) — error rate for the affected endpoint should drop to baseline within minutes.

  2. Check application logs for the specific exception that was reported — confirm it is no longer appearing.

  3. Run a manual smoke test of the affected user flow end-to-end.

  4. Monitor for 30 minutes before declaring the incident resolved.

  5. Write a post-mortem (for major incidents): what happened, timeline, root cause, resolution, how to prevent recurrence.

  6. Backfill any missing test coverage — the hotfix exposed a gap in your test suite.

  7. Update your CHANGELOG.md or GitHub Release notes.

  8. Close the incident in your incident management tool (PagerDuty, Opsgenie, etc.).

Note
After the dust settles, add a regression test for the bug that caused the hotfix. A bug that reaches production once is likely to be introduced again unless there is a test guarding against it.