The thing missing with a lot of these branch management posts is release management… because it’s lovely to live in an ideal happy-path world, but what happens when main is tagged for release, only some customers update, main moves of with multiple breaking changes, and only then do some customers require fixes to their releases (who could all be on different i.e even older tags)?
Do you take their tagged release, fix it there, and then send them that branch release with the fix, or do you send them a fix on current main - you know, the main that is now a million releases ahead with multiple breaking changes? And what about all the intermediate release tags? Do you fix each one there too if they have the problem, or do you only update when customers on those releases start having that issue too?
And if you fix to their old tagged release which is incompatible from main, does this mean you have to do this fix twice i.e on their tagged release and also fix it for main? But what if this fix affects other people who are all on different branches too? Now… times this by 20 different customers all running different hardware and different branches with different problems :(
Maybe my comments are off topic, and don’t get me wrong - I prefer “trunk is releasable” motto, but I think maybe as an industry we should all come up with an Acid Test (like the only CSS Acid Tests) so we can through all these branching strategies into the ring
Trunk-based development fits nicely when you have a single deployment product like a SaaS and you don't need to maintain old versions of your software. You only have one prod environment.
If you build a software that you distribute so people can deploy it themselves (a library, a self-hostable solution, ...), then you most likely semantic versioning. In that case, the best model is to use what semantic release offers.
If you need to support multiple versions at the same time, you need to extend TBD in some way.
We just cherry-picked stuff back to release branches, if we needed a fix.
I've commented about this before.
The answer is development branches are forbidden but releases still use a kind of branching approach.
When you make a release you use commit A from main, then development continues, commit B adds a feature, and maybe commit C fixes a serious bug.
You don't want to make a new release at C because it includes new non tested features, instead you cherry-pick fixes to your release, test the new release candidates, and release that when ready.
Development still happens in main however.
Another big tool to minimise these problems is to separate the concept of feature release from the concept of binary release. You don't have to make a true deployment to release new features or roll them back, just use a toggle switch.