I'm working on a project where we need to patch an old version of our library. We publish/release this package to GitHub Package Registry and (needless to say) use semantic versioning. This is our first time patching a prior release and I'm having a hard time identifying the best practice for this.
I came across this thread that mostly seems to work except for a couple issues albeit major ones. Following what was described in the comment I linked above, here are the steps I've tried in a test repo. In this example, let's assume there are two tags that exist on the main branch: v1.0.0 and v2.0.0, and I need to patch the v1.0.0 release with a hotfix (v1.1.0).
- checkout the v1.0.0 tag (
git checkout v1.0.0) - create a hotfix branch (
git checkout -b hotfix-v1.1.0) - commit changes to hotfix branch (
git add .;git commit -m "Hotfix v1.1.0 changes") - create hotfix tag on hotfix branch (
git tag v1.1.0) - switch to trunk (
git checkout main) - merge hotfix branch into trunk (
git merge hotfix-v1.1.0 --no-commit --strategy ours) - commit merge (which requires manual intervention) (
git commit) - push up hotfix tag (
git push --tags) - delete local hotfix branch (
git branch -d hotfix-v1.1.0)
After these operations, I checked origin in GitHub and found that the v1.1.0 hotfix was present in the latest commit (good) and the latest state of main had the code from v2.0.0 (good). It also had the new v1.1.0 tag (good).
There are a couple issues, though. First, when I switch to the hotfix tag (v1.1.0) in GitHub, there is the following alert: "This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository." I'm unclear on the implications of this, but it doesn't seem like a good thing.
The bigger issue is that the committing, merging, etc. I executed ignore the fact that my main branch is protected by various status checks. Being able to ensure existing workflows and checks are included in this hotfix process is a requirement.
So what is the best practice for patching a prior release? Thanks in advance for any input.
I'll just address the issues you're having with your current workflow.
Moving forward, you likely want a variation on gitflow where you make a release branch off v1.0.0 and leave it open. If you want those fixes also in v2 you'd cherry pick them back into v2 in a separate feature branch. You would not merge v1 into v2, this risks conflicts and resurrecting old v1 code in v2.
The problem is you're merging locally where there are no checks. No workflow should be merging nor committing directly to main.
Instead, merge using pull requests. This allows checks to run on the branch and review to happen before merging to main.
NOTE: v1.1.0 indicates new features have been added. A release containing only bugfixes should be v1.0.1.
Despite what
git logand Github show, Git history is not linear. It is a graph. Each commit is connected to its previous commit(s). You can see this withgit log --graph --decorateor a tool such as Git Kraken.Branches and tags are just labels which point at a commit.
What Git is telling you is the commit is not reachable from any branch.
Let's walk through how this happened.
You start like this:
Commits only connect to the left. D can reach C, B, and A. C cannot reach D.
The v1.0.0 tag points at commit C. The main branch points at commit F.
A, B, C, D, E, and F are all reachable from main.
Here both your local repository and the copy on Github (your "origin" remote) are the same.
You've made your hotfix branch, added a commit, and tagged it.
hotfix can only reach G, C, B, and A.
G is not reachable from main.
Nothing has been pushed to Github.
You've merged your hotfix branch into main. M is a merge commit with both F and G as its parents. Locally, G (and thus v1.1.0) is part of both the main branch and hotfix branch.
Here's where it went wrong. Git push/pull is very efficient and will only push as much as it needs. Since you only pushed tags, it only pushed the commits it needed to populate the history of your tags. That means it only pushed commit G.
So as far as Github is concerned, commit G cannot be reached by any branch. This isn't necessarily a bad thing, the commit can still be referenced via the tag.
If you
git push --allGit will push all your tags and branches, and any commits necessary to populate their history. That means it will push that main now points at M. This means it must push commit M. Then G will be connected to main on Github.