Hi William,
The release train in your GitFlow workflow model is what stops you iterating, and long-running feature branches are what jam up a naive trunk-based model.
Where I would gently push back is on the proposed hybrid. Reintroducing a develop branch to hold long-running work solves the blocking problem, but it quietly brings back the thing you were trying to escape. develop becomes a second long-lived integration branch, it drifts from master, and you are back to painful merges and a de facto release train, just a shorter one. It tends to erode into Git Flow again over time.
The core issue is not really the branching model, it is that you are using branches to hold unfinished work out of production. Trunk-based development solves that a different way: short-lived feature branches only, everything merges to master quickly, and you decouple "deployed" from "released" so that merging something is safe even when it is not ready for users yet.
The way I run this on Databricks:
One main branch, and short-lived feature branches that live days, not weeks. A branch that needs two weeks of testing is the smell to design out, usually by splitting the work so pieces can land safely behind a flag or simply as unused code paths.
Deployment is driven by tags, not by branch-to-environment mapping. main deploys continuously to DEV via the CI/CD pipeline. A release is cutting a tag, and the pipeline promotes that specific tagged commit through TEST and on to PRODUCTION. This gives you an immutable, auditable release artifact and breaks the one-branch-per-environment coupling that is making your matrix complicated. Databricks Asset Bundles fit this well, since you can hold environment-specific config as targets and deploy the same bundle to each.
For the long-running feature problem specifically, the honest answer is that the fix is upstream of branching. You raised that feature flags are hard when schema and query changes are involved, and that is true, but it is usually solvable with expand-and-contract migrations: add the new column or table, backfill, run old and new paths in parallel, then remove the old once the new is proven. It is more discipline than a develop branch, but it keeps you genuinely continuous and it scales to multiple concurrent features, which the develop-branch approach does not.
For hotfixes, this model handles them naturally: branch from main, fix, merge, tag, promote. No separate flow needed.
I would be cautious about the financial-complexity argument being a reason to keep long-lived branches. High test burden is a strong reason to invest in automated test coverage and staged promotion, but long-lived branches actually make the risk worse, because they batch up large, hard-to-review changes. Smaller, more frequent releases are usually safer in exactly the high-stakes environments where people assume the opposite.
Best,
Stephen