- 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
- 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.
- 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.
-
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.
- develop is not stable enough to test, and not isolated enough to experiment.
- develop is an integration branch, a testing branch, a next-release branch, and a staging area for partially complete work.
- 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.
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,
- 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
- 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.
- quarantine – optional 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.
- 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.
- 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.
- 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.
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 sandbox – sandbox is only needed when you want a sandbox/integration area.
- Only one version → use only master –
release/V2026.Q1,release/V2026.Q2are 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..
- 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.
- 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.
- 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