11 February 2026

CleanCut-Flow as flexible branching strategy for Git

Constraints:
  • We want to be able to release a version on demand.
  • We need to support multiple versions when required.
  • We need a solution that scales with our current and future needs.
GitFlow
Branches:
  • feature/... – feature branches for separate development and testing, created mostly from develop.
  • bugfix/... – bugfix branches for separate development and testing, created mostly from develop (or from the relevant release branch).
  • release/V2026.Q1..., release/V2026.Q2... – previous (major/minor) releases (hotfixes, required changes).
  • master – current version (2026.Q3...).
  • develop – current & next release – integration testing of development & fixes.
Flow:
  • Create a feature branch (from develop).
  • Loop (implment → fix → test → commit).
  • Merge into develop.
  • Loop (hand over for testing → develop → fix → test → commit → merge).
  • Accept.
  • Optionally merge to master and maybe release/V2026.Q2.
  • Release, or wait for the next release.
Problems:
  • It heavily depends on estimations, planning, number of testers, etc. – introducing many points of failure, because it tightly couples releases to the current state of develop:
    • You must correctly estimate which features will be finished in time.
    • You must know QA capacity in advance.
    • You must assume that priorities won’t change too much mid-cycle.
    • Any task that slips the release or fails QA can potentially require additional work from the whole team.
  • Any task changes or cancellations require additional protocols for removing changes from develop. This is directly counter-productive: it adds work exactly when you have the least time. As a result, GitFlow makes easy tasks easier and hard tasks harder.
  • Any task that is in develop needs tracking for completion / non-completion.
  • You are basically working on experimental code – there is no presumption of code quality on develop.
  • Any changes that are reverted from develop require excessive work to make them visible for merge again and to monitor them. To do this properly, you would need to double-check all changes that came afterwards.
  • Any trial or experimental changes are risky because they automatically pollute the workspace once merged – including changes that seemed trivial at first.
  • Partial changes that technically "work" but alter application behaviour are painful, because we need to extract them back out – and they may already be integrated into other changes.
  • Any easy collaborations between teams are basically dead – any commit can entangle a developer in the full release cycle.
  • Branching out from develop for a new version makes changes incompatible with previous versions by default.
In short:
  • develop is not stable enough to test, and not isolated enough to experiment.
In long:
  • develop is an integration branch, a testing branch, a next-release branch, and a staging area for partially complete work.
This guarantees:
  • Pollution by unfinished behaviour, expensive rollbacks, and coordination overhead.
  • It also creates a false signal – a low number of merge requests does not indicate quality; it may simply mean that people silently pull from a polluted develop, absorbing partial or untested changes. Potential conflicts and behaviour changes get hidden inside these pulls instead of being visible as explicit merge conflicts – it’s a kind of survivorship bias.
Implications!
If your process requires:
  • tracking reverted features,
  • monitoring merge visibility,
  • remembering which tasks were undone,
  • struggling with pollution from old branches,
  • constant firefighting QA on develop just to keep it usable,
then with GitFlow:
  • your branching strategy is compensating for missing isolation,
  • you are moving merge costs into intricate bugs in production,
  • development time is silently moved into excessive Scrum meetings and coordination.
CleanCut
It can be considered an evolution of GitHub-Flow.
Branches:
  • V{versionPrefix}/feature/{committer}/... – feature branches for separate development and testing.
  • V{versionPrefix}/bugfix/{committer}/... – bugfix branches for separate development and testing.
  • unstable/... – prefix for branches with changes that are unstable, missing time/resolution or are outside current support scope. This is a place where we park partial work when fature/bug priority changes or the team has no time to finish it. The team typically reviews these branches after each sprint.
  • backup/... – prefix for sandbox, feature, backup and bugfix branches and for changes temporarily outside current consideration.
  • release/V2026.Q1..., release/V2026.Q2... – release branches of previous minor versions (hotfixes, required changes for those versions).
  • master – current version: changes that are already released, waiting for release, or being tested for stability before release.
  • quarantineoptional branch that collects merges and commits before they are moved to master and tested as a single set.
  • sandbox – integration test, development, and fixing. After each minor version it is moved to backup/.../sandbox and recreated from master (or quarantine) with relevant branches added. Recreation can also be done on demand when pollution happens.
  • develop – integration development – optional branch, used only in new/greenfield projects that are intentionally messy, evolving fast, and where the consequences of bugs are minimal.
Rules:
  • Stable branches in CleanCut are master and release/... (and optionally support/...).
  • A new minor(quarterly) version only requires: creating a new branch release/V2026.Q3 from master, then increasing the master version to 2026.Q4.0, and optionally recreating sandbox (develop).
  • New feature/bugfix branches should be created from a release or master branch, not from sandbox nor develop.
  • Before pushing any work into a stable branch, it should be squashed into one or a few comprehensive commits. Optionally, you can create a new branch with S{s} added into the branch name, where {s} is the squash version. This helps track history and creates a natural manual for similar changes.
  • Re-merge into sandbox after squash to ensure that feature changes created from master do not introduce collisions – this is purely a structural compatibility check.
  • Branches should contain a control file that prevents invalid merges, for example blocking merges from sandbox to master.
  • Best practice for working on the same area is: either working sequentially (one after another) or creating a shared work branch for all participants.
  • Creating a work/test branch from sandbox (develop) is acceptable when researching the source of a bug that appeared after testing and does not occur in stable branches.
  • Including version and committer in the branch name allows easy monitoring of unfinished/dropped work, and gives hints about estimation when picking up the task again.
  • In some cases the sandbox branch can be omitted.
  • In some cases only the master branch is used.
  • To minimize collisions when possible:
    • library changes should be done separately,
    • non-conflicting / incremental changes (e.g. configuration/properties) should be done separately.
Flow:
  • Create a feature/bugfix branch from the lowest required stable branch: master, release/V2026.Q2, release/V2026.Q1.
  • Loop (implement → fix → test → commit).
  • Squash if needed.
  • Merge into sandbox for integration testing.
  • Loop (hand over for testing → to sandbox → fix → test → commit → merge).
  • Accept.
  • Squash (final squash if needed).
  • Merge into each required stable branch, starting from the lowest required: release/V2026.Q1, release/V2026.Q2, then master (or quarantine if used).
  • Release decision.
Key characteristics:
  • This model ensures that merge conflicts are indicators of possible problems, not the source of them.
  • sandbox can be discarded at any moment.
  • Cleaning up old branches and monitoring is extremely easy.
  • "one feature" = "one commit" on stable branches, making history and rollbacks simpler.
  • Control files reduce accidental or invalid merges that break the model.
  • Experimental/complex work can be dropped and picked up at any time, balancing evolution and collisions.
  • Isolation of unfinished / unstable work.
  • Branch naming clearly states intent and ownership.
  • Conflicts in this model help prevent bugs.
Scalability:
When CleanCut is used as a flexible framework, it can become a single company-wide convention. The only mandatory rule is to create feature/bugfix branches from stable branches, along with the naming convention.
  • Only rare changes → don’t use sandboxsandbox is only needed when you want a sandbox/integration area.
  • Only one version → use only masterrelease/V2026.Q1, release/V2026.Q2 are for reference only.
  • Need more detailed history → skip squash – squash is not required; it’s just recommended for easier rollback and analysis.
  • Great tests / strong CI → skip quarantine
  • Need fast release → skip quarantine
  • No need to keep unfinished/parked work → drop unstable branches – features are small and either merged or abandoned quickly.
  • In the simplest case, CleanCut shrinks to: master as the only stable branch, short-lived feature/bugfix branches from master, optional squash before merge..
How can it work:
  • Very simple / small projects
    • CleanCut: no develop, no sandbox, no quarantine, no unstable, no backup, no multi-version release/...
    • GitFlow: with a dirty develop.
  • Single product, strong CI, one or two supported versions
    • CleanCut: no develop, no quarantine unless needed.
    • GitHub Flow: a minimal alternative when multi-version support is not needed.
  • Complex, enterprise-style, multi-version, limited QA
    • CleanCut: no develop.
    • GitFlow: typically with a shared develop branch.
Introduction over time!
  • Never to late to:
    • Negotiate and enforce a branch naming convention.
  • New Project:
    • Use master and feature branches.
  • Demo + early distribution:
    • Work on develop, then merge to master and use feature branches.
  • Stable Project:
    • Use master and feature branches.
  • Stable Project that keeps growing:
    • Use master, sandbox, and feature branches.
  • Company with many projects, people move between teams:
    • Use squash merges to reduce pain when returning to or onboarding to a project.
  • You want to fix archaic bugs:
    • Work via sandbox.
  • Project needs high quality, multiple possible solutions:
    • Use sandbox to compare and integrate solutions.
Variation:
  • When master is our main focus, "create a feature/bugfix branch from the lowest required stable branch" can be simplified to: start from the primary branch only. The primary branch may be named main, master, or trunk, as long as it is clearly understood and consistently used.
  • release branches could be clarified to release & support: release/V2025.Q4..., support/V2026.Q1..., support/V2026.Q2....

0 comments / komentarz(y):

Post a Comment