Hotfix Flow
Use this repository skill only when a defect already released on main must be fixed before the work waiting on develop is ready to ship.
Every other fix is an ordinary task. Use develop-task-flow and let the fix ride the next release.
When This Applies
All three must hold. If any one fails, this is not a hotfix.
- The defect is reachable from
main, so people already have it. - Harm keeps accumulating for as long as the released state stands. See Hotfix Triggers — the user calling it urgent is not that.
developholds work that must not ship yet. Whendevelophas nothing unreleased, there is no hotfix: fix it withdevelop-task-flowand release normally.
Hotfix Triggers
Whether a defect deserves to bypass the develop queue is a judgement, and it is made while something is on fire. So the judgement is not made here: the project writes the conditions in advance and this run only matches against them.
Resolve the list from the ## Hotfix Triggers section of the rubric file, found in the same order the grade uses:
JIG_VERSION_RUBRICenvironment variable.git config --local --get jig.versionRubric(repository override)..jig/versioning.md(the convention).
Accept either spelling of the section title: ## Hotfix Triggers or ## 핫픽스 트리거.
The section holds an anchoring question on a > line and the conditions answering it that the project has already recognised. When the rubric has no such section, use this default and say in the report that it was the default:
Does harm keep occurring and accumulating for as long as the released state stands?
- The released artifact does not install or start
- Data is lost or corrupted
- A credential or secret is exposed
- A published security vulnerability is exploitable
- A released capability is entirely broken for most users
Apply it in this order:
- A listed condition matches. Name it, record it as a
Hotfix-Trigger:trailer next toRelease-Grade:, and continue. - Nothing matches. Put the anchoring question to the user, in terms of what keeps happening while the release stands. A
noends the run: hand the fix todevelop-task-flowand say why. - Nothing matches but the answer is
yes. The list is short by one condition. Propose that condition, add it to the## Hotfix Triggerssection, and commit that change on its own before the hotfix starts. Then continue from step 1 with the condition now listed.
Step 3 is not a formality that lets a hotfix through. It is what stops the list from silently becoming whatever the current run needs: the addition is a policy change, committed separately, readable later next to every other one.
Urgency asserted by the user is not an answer to the question. Neither is a deadline, a demo, or a release that feels overdue — those describe a schedule, not something the released state keeps doing.
Why the Model Needs a Separate Flow
main normally only moves by the release fast-forward git push origin develop:main, and both jig guards block anything else. A hotfix is the one operation that puts a commit on main that develop does not have.
That divergence is the whole risk. Once main holds a commit develop lacks, git push origin develop:main stops fast-forwarding and github-release refuses to run — correctly, because the alternative is a force push.
So the back-merge is part of this procedure, not a follow-up. A hotfix that lands on main without returning to develop leaves the repository unable to release.
Landing on develop: Merge, Never Cherry-Pick
Bring the hotfix back with git merge main into develop.
Do not cherry-pick it. A cherry-pick copies the change under a new SHA, so main stays outside develop's history and every later develop:main push fails the fast-forward check. The merge is what makes main an ancestor of develop again.
The merge commit itself never reaches the release notes: github-release reads git log <previous>..<version> --no-merges. The hotfix commit is already behind the hotfix tag, so it is not repeated in the next release either.
Release Grade
Grade the hotfix against the repository's version rubric, resolved in this order:
JIG_VERSION_RUBRICenvironment variable.git config --local --get jig.versionRubric(repository override)..jig/versioning.md(the convention).
Apply its ## Decision Order to this fix alone, stopping at the first match, then its ## Hard Rules. Use git diff --name-only origin/main...HEAD as evidence, and read the floor from ## Interface Paths when the rubric has that table. Record the verdict as a trailer on the squash commit body:
Release-Grade: patch
Hotfix-Trigger: The released artifact does not install or start
version-rubric owns the rubric file. Never edit it from here.
Version
- Compute from the latest
vX.Y.Ztag reachable fromorigin/main(git describe --tags --abbrev=0 origin/main), using the graded bump and the rubric's## Version Formatwhen it has one. - A hotfix is usually
patch. It is not automaticallypatch: grade it, and if the fix changes behavior silently the rubric says so. - The tag is created on the commit that landed on
main, not on adevelopcommit.
Safety Rules
- Do not force push.
- Do not bypass git hooks: never pass
--no-verifyto any push. - Push
mainonly asgit push origin hotfix/<slug>:main, and only when it fast-forwards. If it is rejected, stop and report; someone else movedmain. - Stop when
git rev-list --count origin/main..origin/developis0. With nothing unreleased there is no work to protect, so a hotfix only adds steps. Usedevelop-task-flowand release normally. - Do not start a hotfix from
develop. The branch point isorigin/main, or the fix carries unreleased work with it. Thepre-pushguard enforces this: a hotfix push must be exactly one commit ahead ofmain, and a branch taken fromdevelopis many. - Do not include anything beyond the defect. A hotfix that also carries a refactor is an ordinary task.
- Do not widen the trigger list inside a hotfix commit. Adding a condition is allowed and expected over time, but it is proposed to the user and committed on its own before the fix begins, never folded into the fix. A list that grows inside the run it is gating has stopped being a gate.
- Do not leave
mainahead ofdevelop. The back-merge runs in the same session, before the report. - Do not resolve a failed
develop:mainfast-forward by force-pushing; that is the state this skill exists to prevent. - Do not delete branches without explicit user confirmation.
- Do not edit the rubric file.
- Preserve unrelated user changes.
Procedure
- Inspect and confirm the three conditions in When This Applies:
git status --short --branchgit fetch origin --prune --tagsgit rev-list --count origin/main..origin/develop—0ends the run. Report that this is an ordinary task and hand it todevelop-task-flow- resolve
## Hotfix Triggersper Hotfix Triggers and name the matching item. No match ends the run. git log --oneline origin/main..origin/develop— name the unreleased work that must not ship, so the user can see what the hotfix is protecting
- Create the branch from the released state:
git checkout -b hotfix/<slug> origin/main. - Implement only the fix.
- Run the most relevant focused test, then the repository's broader validation when practical. Report any gap.
- Reduce the branch to one commit on top of
origin/main:git reset --soft origin/main- commit once with a
fix:subject, user-facing body bullets, and theRelease-GradeandHotfix-Triggertrailers
- Land it:
git push origin hotfix/<slug>:main. This must fast-forward, and the guard additionally requires it to be exactly one commit ahead ofmain. A rejection there means the branch did not start fromorigin/main; do not work around it. - Tag the commit that is now
mainand publish:git tag <version> $(git rev-parse hotfix/<slug>)git push origin <version>gh release create <version> --title "<version> 🌈" --notes-file <draft>- Resolve the GitHub profile the way
github-releasedoes before anyghcommand.
- Return to develop in the same session:
git checkout developgit pull --ff-only origin developgit merge main— resolve conflicts here, never by dropping the fixgit push origin develop
- Verify the invariant is restored:
git merge-base --is-ancestor origin/main origin/developmust succeed. Until it does, the next release cannot run. - Report.
Release Notes
Follow the github-release note format: ## Changes with the section its commit prefix selects (fix: → ### 🐛 Fixes), then a ### Summary in the language the repository already uses.
Say plainly that this release came from main and that develop work is not included. Someone reading two adjacent tags should not have to guess why the second one carries less.
Final Report
- Branch, and the
origin/maincommit it started from - Files changed and tests run
- The trigger that matched, and whether it came from the project's list or the shipped default
- Graded bump, the rubric question that decided it, and the recorded
Release-Grade - Version tagged and the release URL
- Back-merge result and the
merge-base --is-ancestorverification - Unreleased
developwork that was deliberately left out - Commands that could not run and why