# Future Versioning and Branching
This is a fairly unstructured braindump of my longer term thoughts about versioning and branching. Since [Cunningham's Law](https://meta.wikimedia.org/wiki/Cunningham%27s_Law) always seems to yield better results, I declare that whatever I have here to be our new release process. :wink:
# TL;DR
1. Simplify our release numbering.
2. Branches for everything. Hotfix in main? Create an upstream branch. Hotfix in ubuntu/devel? Create an ubuntu/devel hotfix branch.
3. Merge hotfix changelogs back into their respective branches.
# Upstream Release Numbers
(Jumping down to the examples might be more productive than reading these blocks of text)
Regular upstream release has `<major>`.`<minor>` (I know it's year based, but you know what I mean).
Hotfixes get a .`<patch>` that gets incremented.
These versions all get reflected into ubuntu versions.
If we SRU without first doing an upstream release (seems more rare these days), we'll increment `~<series>.<patch>` instead.
# Devel Release Numbers
Since pre-releases (i.e., `ubuntu/devel`) happen outside of the normal release schedule, `ubuntu/devel` will get a different versioning scheme:
`<next_release>~<patch>g<hash>-xubuntuy`
For example, if we just released `23.1`, then we added 5 more commits to main with the most recent commit being `#12ab34cd`, then release that to devel, the devel version would be:
`23.2~1g12ab34cd-0ubuntu1`
Upstream hotfix version numbers will NOT be encoded in the devel version number. If we then have an upstream hotfix as `23.1.1` with hash `#12ab34ce`, the devel version would be:
`23.2~2g12ab34ce-0ubuntu1`
We use the next release number in devel so that upgrades from stable series to devel will result in moving to the latest version number. If we had instead used `23.1-5g12ab34cd-0ubuntu1` as the devel version number, then a hotfix release of `23.1.1` into stable series means that the stable series could never upgrade into devel because `23.1-*` sorts lower than `23.1.1`.
We don't use the hotfix number in ubuntu/devel because it would be misleading. If stable series `23.1.1` contains `23.1` + the single hotfix commit, then ubuntu/devel shouldn't use the same number when it contains an upstream snapshot containing every single commit up to the hotfix commit.
The incrementing number between `~` and `g` is NOT the number of commits since a tag. It is simply a number that gets incremented every release. It would be confusing to use a tag because given the version number, we don't know which tag it is counting from.
# Daily Release Numbers
Because dailies go into their own PPA, they can follow a separate scheme entirely. To make it easy to know what is in the build at a glance, yet still allow for upgrading to new versions in the future, the version number should be `<major>.<minor>.daily-<UTC-datetime>-<commit>~<series>`.
## Examples
In these examples, I'll use 12ab34cd as the commit number, even though they will be random.
### Upstream release
* `23.1`
### Ubuntu/devel based on upstream
* `23.1-0ubuntu1`
### Ubuntu/jammy based on upstream
* `23.1-0ubuntu0~22.04.1`
(`0ubuntu0` because 23.1.0 was never released for this series)
### After hotfix
* Upstream: `23.1.1`
* Ubuntu/devel: `23.2~1g12ab34cd-0ubuntu1`
* Ubuntu/jammy: `23.1.1-0ubuntu0~22.04.1`
### SRU without upstream release (i.e., downstream hotfix)
* Original upstream: `23.1.1`
* Original ubuntu/jammy: `23.1.1-0ubuntu0~22.04.1`
* Fixed ubuntu/jammy: `23.1.1-0ubuntu0~22.04.2`
### First upstream snapshot into ubuntu/devel
* `23.2~1g12ab34cd-0ubuntu1`
### Next upload into ubuntu/devel
* `23.2~2g12ab34ce-0ubuntu1`
### Random daily build for jammy
* `23.1.daily-20221001050505-495cb85c~22.04`
These are fairly readable by humans. These can be incremented by humans. With this scheme we can update the debian changelog by hand if we want/need to...which seems to be fairly often :smile:
# Upstream branching
At upstream release, we update the changelog and bump the version number.
If we need a hotfix, create a `<major>.<minor>.x` (that's a literal 'x') branch for upstream. Same rules apply for releasing a hotfix: update the d/changelog and bump the version.
After release, we **merge the changelog and version back into main**.
## Example
We released 22.4<br/>
Changelog:
```
22.4:
* thing 1
* thing 2
```
`version.py`: `22.4`
Oh no! We broke the world. Create branch `22.4.x`. Cherry-pick the fix onto `22.4.x`. Update changelog and `version.py`. Commit. Tag `22.4.1` on the `22.4.x` branch.
Changelog:
```
22.4.1:
* cherry pick of fixing the world
22.4:
* thing 1
* thing 2
```
`version.py`: `22.4.1`
^ This ChangeLog and `version.py` should then get merged back into main.
The only time we wouldn't need a separate branch is if the hotfix is close enough to release that we're comfortable tagging main and upstream snapshotting to the hotfix **without skipping commits**.
# Ubuntu branching
Apart from devel, the ubuntu branch should **only** receive upstream snapshots from main (or a main-based release tag). If we need to release a hotfix, then create `ubuntu/<series>-<major>.<minor>.x` branch. Once released, merge `d/changelog` back to `ubuntu/<series>`. This process would be followed regardless of if we have SRUed or not.
## Example
(assume all of this is pre-feature freeze)
Upstream released `22.4`
`ubuntu/devel` then upstream snapshots and releases `22.4` into devel series with `22.4-0ubuntu1`.
20 commits go by and we want to release to devel again. We upstream snapshot and release with version number `23.1~1g12ab34cd-0ubuntu1`
Oh no! We broke the world! `22.4.1` gets released upstream as described above.
For `ubuntu/devel`, we upstream snapshot as always. New ubuntu/devel version number would be `23.1~2g12ab34ce-0ubuntu1`
For the stable branches, since `22.4.1` is branched from main, we don't upstream snapshot. Instead create branch `ubuntu/jammy-22.4.x` from `22.4-ubuntu1`.
Then merge `22.4.1` into `jammy/devel-22.4.x`.
Apply quilt patches and release. Tag `22.4.1-0ubuntu0~22.10.1` on `ubuntu/jammy-22.4.x` branch.
Merge `d/changelog` and any relevant packaging changes back into `ubuntu/jammy`.
# Quilt patches
cpick-style cherry-picks should be uncommon if we use additional hotfix branches. Manual patches for series-specific behavior would still need to be maintained and refreshed, but `new-upstream-snapshot` and `gbp pq` can help with that. A cpick may still be necessary in the case we SRU without an upstream change, but that's no longer a common use case.
# Old Discussion (probably not relevant anymore but here for history's sake)
## Pros
* We should never get merge conflicts with `version.py` or version numbers.
* Never need to undo `cpick` files and rarely need to create them.
* Process is the same upstream and downstream: Branch from mainline, fix and release on branch, merge changelog back.
## Cons
* Branches branches everywhere. I'm not convinced that's really a problem though. Look at the top 10 python libraries on Github, and from an upstream perspective, it's super common to keep several `<oldrelease>.x` branches. The more annoying thing is having a ton of downstream ubuntu branches in our github. I don't think having so many branches is very uncommon though. E.g., netplan has an SRU exception, and here's a list of their packaging branches: https://git.launchpad.net/ubuntu/+source/netplan.io/refs/heads . They're named "applied" rather than hotfix branches, but it's still the same concept.
* After bumping the `<major>.<minor>` version numbers, there's no reason to keep the old branches around. Again, using netplan as an example, scroll down to their tag list. Once the tag exists and the version is obsolete, we can delete the branch.
* Merging back patch numbers and changelogs from hotfix branches is a new process for us. It may wind up being more ad hoc than running a simple tool every time.
## Other Discussion
* **Why merge back?** It's annoying but seems like the "right thing to do". If somebody is reading a changelog on the main branch, they should see the most recently released version, not something older. That's less relevant downstream, but also every project I've looked with a changelog lists all interim releases in their changelog.
* **What about tags instead of branches?** That's a possibility, but leads to unfortunate consequences:
1. Reviewing is harder because PRs aren't possible
2. Scary messages in github about commits belonging to other remotes
3. Adding more commits for more hotfix releases is harder without a branch
* **What about that discussion with Christian about using source format rather than quilt?** I'm personally leaning against that idea for a few reasons:
1. Quilt is now the default way to do things in debian, and most tools are built around the `3.0 (quilt)` format.
2. With `gbp pq`, we can get the benefits of using git for patches without much overhead. We just need to make sure we're consistent about which DEP-3 headers we're using.
3. The long-lived quilt patches usually haven't caused much headache. It's almost always the cpick creating and dropping that has been an issue, and with this process, those mostly go away.
4. I'm still a fan of the idea of moving to having a parent `debian` branch with individual series branches being children. That would mean most changes get created once, and then we rebase them down into each series. That sort of change feels longer-term and not dependant on what we decide to do here. Let's fix the leaking roof before we decide to add improvements.
* **Can we always upstream snapshot into `ubuntu/devel`?**
We recently pushed the same cherry-picks into `ubuntu/devel` that we pushed into our SRUs. Is that sensible moving forward or should we always upstream snapshot `into ubuntu/devel`?