Skip to Content
InfraGit strategy

Git Strategy

This project uses GitFlow adapted for per-platform releases. The KMP mono-repo ships six independently versioned artifacts (Android, iOS, Desktop, Server, Web, WASM), and mobile releases sit in app-store review for days while main keeps moving — a single-trunk model can’t absorb that reality, so we keep a stabilization line per platform.

This doc owns how work flows through branches. Two sibling docs own the adjacent concerns:

  • Versioning — the VERSION file, tag scheme, and how build scripts read versions.
  • Release checklist — the step-by-step execution when you’re actually shipping.

Branch model

BranchCut fromMerged intoMerge stylePurpose
mainProduction mirror. Every commit is a shipped artifact and is tagged by a publish workflow.
developmain (once)Integration line. Default base for feature branches.
feat/*, fix/*, chore/*, docs/*, refactor/*developdevelopsquashDay-to-day work. Short-lived.
release/{platform}/{version}developmain (then back-merge to develop)merge commitPer-platform stabilization. Only bug fixes and the /VERSION bump.
hotfix/{platform}/{version}tag {platform}/v{X.Y.Z} on mainmain (then back-merge to develop)merge commitFix a shipped artifact without waiting for the next cycle.

main accepts merges only from release/* and hotfix/*. Feature branches never target main directly.

Naming conventions

Branches:

  • Feature work: feat/<slug>, fix/<slug>, chore/<slug>, docs/<slug>, refactor/<slug>
  • Release: release/{platform}/{version} (e.g. release/server/1.2.0, release/android/1.1.0)
  • Hotfix: hotfix/{platform}/{version} (e.g. hotfix/server/1.1.1)

Platforms: android, ios, desktop, server, web, wasm.

Tags: {platform}/v{X.Y.Z} — e.g. server/v1.0.0, android/v1.0.0. Created by publish workflows only; never tag by hand.

Pull requests

  • Default base: develop.
  • main accepts only release/* and hotfix/* PRs.
  • Merge style:
    • Squash for feat/*, fix/*, chore/*, docs/*, refactor/*develop.
    • Merge commit for release/* and hotfix/*main, and for the back-merge maindevelop. Preserving the release lineage matters for hotfix cherry-picks.
  • CI must be green before merge. Solo self-merge is fine, but only after CI passes.
  • Size: small PRs. Split shared-code refactors from feature landings; land the refactor first.

Commit messages — Conventional Commits

Format: type(scope): subject — imperative mood, ≤72 chars for the subject.

Types: feat, fix, chore, docs, refactor, test, build, ci, perf, style, revert.

Scopes — either a platform or a feature (or both, comma-separated):

  • Platforms: server, android, ios, desktop, web, wasm, shared.
  • Features: finance, tasks, habits, journal, calendar, study, nutrition, timers, workout, work, books, notifications, dashboard, onboarding, and anything else living under shared/.

Breaking changes: ! before the colon, plus a BREAKING CHANGE: footer explaining migration.

Release commits: chore(release): {platform} v{X.Y.Z} — as release-checklist.md already uses.

Examples:

feat(finance): add net-worth widget to dashboard fix(server): reject expired refresh tokens on WebSocket upgrade refactor(shared,android): extract timezone helper into shared/util feat(server)!: rename POST /meals payload field servingSize -> servingsPerMeal chore(release): server v1.1.0

Per-platform release flow

For each platform independently:

  1. Cut release/{platform}/{version} from develop.
  2. Bump the platform’s keys in /VERSION, move [Unreleased][X.Y.Z] in the platform’s CHANGELOG.md, and if iOS is affected run scripts/ios_generate_version_xcconfig.sh. Commit as chore(release): {platform} v{X.Y.Z}.
  3. PR release/*main. Merge with a merge commit (not squash) once CI is green.
  4. Trigger the platform’s publish workflow from Actions on main. It tags {platform}/v{X.Y.Z} on the merge commit.
  5. Back-merge maindevelop and delete the release branch.

The verification steps (spot-check the artifact, confirm the tag, etc.) live in release-checklist.md.

Hotfix flow

Same shape as a release, but starting from a shipped tag rather than develop:

  1. git checkout -b hotfix/{platform}/{X.Y.Z+1} {platform}/v{X.Y.Z} — cut from the tag on main.
  2. Fix the bug. Bump only that platform’s key(s) in /VERSION. Update the platform’s CHANGELOG.md. Commit as chore(release): {platform} v{X.Y.Z+1}.
  3. PR to main (merge commit). Trigger the platform’s publish workflow.
  4. Back-merge maindevelop. If the fix also applies to develop’s next release, the back-merge carries it; otherwise resolve conflicts to preserve the develop-line behaviour.

Cross-platform coordination

Three rules that only make sense once written down:

  • Server-first for API changes. Any change to REST or WebSocket contracts ships on the server before the clients that consume it, and the server keeps the old contract until the minimum supported client version has caught up. Mobile update lag (store review + user delay) is real — plan for weeks, not hours.
  • shared/ changes are all-platforms changes. A commit touching shared/commonMain must build on every active platform before it merges to develop. If a platform is mid-release/*, decide whether the shared change is a fix (cherry-pick to the release branch) or a feature (waits for the next cycle).
  • Concurrent release branches are fine. Two platforms can stabilize in parallel (e.g. release/server/1.2.0 and release/android/1.1.0). They only conflict on /VERSION — resolve by keeping each edit scoped to its own keys.

Branch protection & CI

Enforce on both main and develop:

  • PR required for all changes; direct pushes blocked.
  • CI green required to merge.
  • Force-push blocked; branch deletion blocked.

ci.yml runs lint + tests on every PR to develop or main, and on every push to those branches. Publish workflows remain workflow_dispatch and always run against main.

Quick reference

BranchCut fromMerged intoMerge styleTagged by
feat/* / fix/* / chore/* / docs/* / refactor/*developdevelopsquash
release/{platform}/{version}developmain → back-merge to developmerge commitPublish workflow, on main
hotfix/{platform}/{version}tag {platform}/v{X.Y.Z} on mainmain → back-merge to developmerge commitPublish workflow, on main

Notes

  • iOS follows the same branch flow even though its publish step is still Xcode-manual (no GitHub Actions workflow yet). The release/ios/{version} branch still exists to house the version bump and Version.xcconfig regeneration; the “trigger the publish workflow” step becomes “archive from Xcode”.
  • develop didn’t exist before this doc. Bootstrapping: git checkout main && git pull && git checkout -b develop && git push -u origin develop. Enable branch protection on both branches afterwards.