Un-f*ck your CICD and Branching Strategy

Un-f*ck your CICD and Branching Strategy

Let’s talk about a CI/CD anti-pattern that needs to die: environment branches. You know the ones - dev, qa, stage, prod. It seems logical at first, but over time it leads to pain, confusion, and chaos.

Modern teams should instead rely on short-lived feature branches and artifact-based promotion - a strategy that dramatically improves clarity, agility, and stability in your pipeline.


Why Short-Lived Branches Matter

Short-lived branches reduce complexity. The longer a branch lives, the more it drifts from the mainline, increasing the chance of merge conflicts, integration bugs, and confusion about what’s actually deployed.

By keeping branches short-lived:

Faster Feedback: Changes are merged and tested quickly, reducing integration risk.

Less Merge Hell: Avoid tangled PRs and back-and-forth reviews.

Better CI Hygiene: Every commit triggers a fresh, clean build.

Tighter Control: You know exactly what feature or fix each branch introduces - no bundling or guessing.

Supports Immutable Builds: When every branch produces a build artifact, you have a traceable lineage of what was built, tested, and released.

The Core Problem

When we test something in a lower environment (say QA), then rebuild it before pushing to production, we're introducing risk. A fresh build is not the same build. Even with the same code, dependencies, timestamps, environment variables - anything can introduce variance.

So why do we keep doing this?

The Better Way: Promote Artifacts, Not Branches

Instead of branching for environments, build an immutable, deployable artifact for every commit on every branch. Whether it's a .jar, .tar.gz, or a Docker image, the idea is the same - treat your build as the unit of promotion.

Tag it. Store it. Deploy it.

Why This Works (and What It Solves)

Hotfixes: You can patch main, build a new artifact, and promote just that. Or maybe create a branch from an existing tag, patch it, and promote it.

Parallel Features: You can release features in any order because builds are isolated. If you need 2 features that are in different branches, simply merge them together and build! There's no need to figure out how to get them into some long-lived branch that may have other half ready features integrated.

Rollback: Want to roll back? Just redeploy a previously tested image. No rebuild required.

Auditability: You know exactly what’s running in each environment - and it was tested.

Implementation Tips

1. Tag your images

Use meaningful tags like:

myapp:feature-login

myapp:v1.2.3

2. Release Candidate Flow

If you're working on a small team, you could use a local script that ensures a clean Git state (no untracked or modified files)

Reads a VERSION file with a -dev suffix during development

Finalizes the version (removes -dev, updates metadata like pom.xml, package.json, etc.)

Tags the commit (e.g. v1.2.3)

Pushes the tag and updated VERSION (e.g. bumps to 1.2.4-dev)

Builds and pushes the final artifact

Or if you want to perform these tasks on CI , then build/store artifacts for each branch or PR. And use GIT tags to identify release versions with a semantic naming convention.

3. CI Automation

Wrap this in a CI workflow so it's consistent, repeatable, and foolproof.

My favorite method involves building a docker image for every tag/branch, tests it, and pushes it to the container registry.

This allows you to completely decouple the build process from the deploy process.

More CI jobs, such as deploying to a specific environment can be manually invoked, or if you want to go fully-automatic, deploy every commit to the default branch to a development environment, then every semantic git tag to a higher level environment such as QA/PROD.

If automated deployment to a stable environment is scary - then add automated testing. Don't introduce friction because of fear. Introduce guard rails instead.

Final Thoughts

Don’t contort your release process around a branching model that fights against modern CI/CD practices. Design your app to use runtime environment config. Focus on traceable, reproducible builds. And promote artifacts, not code.

Your future self (and your team) will thank you.

The culture around football apparel reaches from stadium terraces to everyday collections when a tournament or league season gives the design a lasting meaning. The visual identity of France often becomes stronger during World Cup runs and continental competitions. When comparing home, away, and third kit styles, how to choose football shirts is relevant to conversations about collecting, matchday wear, and kit design. For collectors keeps the paragraph grounded in football culture rather than simple promotion.