← Back to list

Branch Strategy and Release Versioning

Keep main releasable, make releases predictable, and avoid versioning chaos

Rituraj Sambherao · 2026-02-11 22:09 · 0 claps · 4.0 min read
#ci-cd-pipeline #software-release #product-shipping
Open on Medium ↗
Wiki topics: ☁️ · DevOps & Cloud

Branch Strategy and Release Versioning

Keep main releasable, make releases predictable, and avoid versioning chaos

← Part 5: Build Speed Engineering | Part 6 | Part 7: Release Automation and Play Console Delivery →

CI/CD becomes real when your team stops asking, “What are we shipping?” and starts asking, “When do we ship?”

That shift depends on two things:

  • A branching strategy that keeps the codebase stable
  • A versioning strategy that makes releases predictable

Android adds extra spice here because of versionCode, Play Console rules, multiple tracks, and sometimes multiple flavors. This part lays down a practical approach that works for most modern teams.

The real goal: main is always releasable

If main isn’t reliably releasable, you end up with:

  • Last-minute “release fixes”
  • Hidden changes piling up
  • Hotfix panic
  • A pipeline that can’t be trusted

Your branch strategy exists to keep main clean, not to create process theatre.

Ship with Confidence. Version with Discipline.

Ship with Confidence. Version with Discipline.

Branch strategy options that work in Android

Option 1: Trunk-based development

This is the modern default for many teams.

  • Short-lived feature branches
  • Pull requests merge into main quickly
  • Main stays green and releasable
  • Releases are created from main using tags

Why it works:

  • Less merge pain
  • Fewer long-running branches
  • Faster integration
  • CI stays meaningful

This is the best fit when:

  • You ship regularly
  • You have feature flags or staged rollouts
  • You want consistent momentum

Option 2: Release branches, used sparingly

Release branches can be useful, but they’re easy to misuse.

A reasonable model:

  • Main stays the integration trunk
  • When you cut a release, create a short-lived release/x.y branch
  • Only stabilization fixes go into the release branch
  • Main continues forward
  • Tag releases from the release branch, then delete it after

This is a good fit when:

  • You need longer stabilization periods
  • Your org requires a formal release train
  • Multiple releases may be supported at once

If release branches become permanent, you’re back in merge hell.

How to choose without overthinking

Here’s a simple rule:

  • If you ship often and can do staged rollouts, prefer trunk-based
  • If you ship less often or need formal stabilization windows, use short-lived release branches

Either way, don’t let branches become a substitute for quality gates. The pipeline should be doing most of the work.

The Android versioning problem

Android has a hard requirement:

versionCode must always increase for Play uploads.

It’s an integer. No cleverness. If you upload a build with a lower or equal versionCode, Play rejects it.

So your versioning strategy must make versionCode growth automatic and reliable, especially across branches, tracks, and hotfixes.

A practical strategy: semantic versionName, automatic versionCode

versionName

Use semantic versioning style:

  • 1.4.0
  • 1.4.1
  • 2.0.0

Even if you don’t follow semantic versioning perfectly, this gives humans a clear handle on what shipped.

versionCode

Make it automatic. The two common approaches are:

Approach A: CI build number based

  • versionCode is derived from a CI run number or timestamp
  • Always increases
  • Easy for pipelines

Pros:

  • Simple to automate
  • Avoids branch collisions

Cons:

  • Less meaningful locally unless you print it

Approach B: Structured versionCode from versionName

Common pattern:

  • Encode major, minor, patch into an int

Example idea:

  • MMmmppbbb style, where bbb is build increment

Pros:

  • Predictable and ties to versionName

Cons:

  • Can be painful with hotfix branches and parallel releases
  • Requires discipline to avoid collisions

For most teams, CI-based versionCode is the least painful.

A clean release flow: tags as the source of truth

A reliable pattern is:

  1. Main stays green
  2. When ready to ship, create a tag: v1.4.0
  3. Release pipeline builds from that tag
  4. Pipeline uploads to Play and attaches artifacts

Why tags help:

  • You can always rebuild the exact release
  • It’s obvious what commit shipped
  • Release notes and changelogs can reference the tag

Your release process becomes auditable without becoming bureaucratic.

Handling hotfixes without drama

Hotfixes are where many teams lose discipline.

Two reasonable hotfix models:

Hotfix model for trunk-based teams:

  1. Create a hotfix branch from the release tag or commit
  2. Apply the fix
  3. Tag a patch release like v1.4.1
  4. Merge the hotfix back into main immediately

This keeps main aligned with what shipped.

Hotfix model with release branches:

  1. Create hotfix on the release branch
  2. Tag patch release from release branch
  3. Cherry-pick or merge into main

The rule stays the same: shipped fixes must land in main. Otherwise you’ll reintroduce bugs later.

Release notes and changelogs: automate what you can

People waste time writing release notes from memory. Don’t do that.

A practical approach:

  • Require PR titles to follow a convention
  • Generate release notes from merged PRs between tags
  • Allow small manual edits at release time

Even basic automation is a win:

  • Less forgotten changes
  • Less “what went out?”
  • Less manual busywork

You don’t need perfection. You need consistency.

Tracks and promotion strategy

Play tracks are a core part of modern release architecture.

A typical flow:

  • Internal testing for validation
  • Closed or open testing for broader coverage
  • Production with staged rollout

Promotion can be:

  • Automatic after checks, if you’re confident
  • Manual, if you want a final human gate

The key is that the pipeline produces the same artifact and promotes it, rather than rebuilding new artifacts at each stage.

Rebuilds create risk. Promotions reduce risk.

Definition of done for Part 6

You’re done when:

✓ Your team has a clear branching model that keeps main releasable ✓ versionCode always increases automatically ✓ versionName is consistent and human-readable ✓ Releases are cut from tags, not from someone's laptop ✓ Hotfixes have a clear path and always get back into main ✓ Release notes are at least partially automated

Once this is in place, you have the backbone for safe automation.

Next: Release automation and Play Console delivery

Part 7 will cover:

  • Building and signing release artifacts securely
  • Uploading to Play tracks
  • Staged rollouts and halt conditions
  • Attaching mapping files and reports
  • Making releases repeatable and low-stress

Series Navigation:

← Part 5: Build Speed Engineering | Part 6: Branch Strategy and Release Versioning | Part 7: Release Automation and Play Console Delivery →


메타데이터
post_id
cf70ca95cf9b
slug
branch-strategy-and-release-versioning-cf70ca95cf9b
url
https://medium.com/@androidmeda/branch-strategy-and-release-versioning-cf70ca95cf9b
canonical_url
https://medium.com/@androidmeda/branch-strategy-and-release-versioning-cf70ca95cf9b
author_url
https://medium.com/@androidmeda
status
ok
fetched_at
2026-07-10 12:09:34