From f1d38527ce3adefd7852d31f3a2abaa3f6d7f22a Mon Sep 17 00:00:00 2001 From: Ulofe Uduokhai Date: Wed, 22 Jul 2026 21:37:30 +0100 Subject: [PATCH] docs(ops): publish public branching and release model (#7627) (#8129) Explain release/* as the active cycle, main as the published line, and tags as ship markers so contributors know where to aim PRs. Co-authored-by: Ulofe Uduokhai <179733406+c4usal@users.noreply.github.com> --- CONTRIBUTING.md | 10 ++- README.md | 12 +-- .../maintenance/7627-branching-model-doc.md | 1 + docs/ops/BRANCHING_MODEL.md | 82 +++++++++++++++++++ 4 files changed, 98 insertions(+), 7 deletions(-) create mode 100644 changelog.d/maintenance/7627-branching-model-doc.md create mode 100644 docs/ops/BRANCHING_MODEL.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 389b79d534..d5395a97cc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -103,13 +103,19 @@ Default URLs: ## Git Workflow > ⚠️ **NEVER commit directly to `main`.** Always use feature branches. +> +> **PR base:** target the active `release/vX.Y.Z` branch (not `main`). See +> [`docs/ops/BRANCHING_MODEL.md`](docs/ops/BRANCHING_MODEL.md) for the +> release-per-branch + tag-at-ship model. ```bash -git checkout -b feat/your-feature-name +# Branch from the active release tip (example: release/v3.8.49) +git fetch origin +git checkout -b feat/your-feature-name origin/release/v3.8.49 # ... make changes ... git commit -m "feat: describe your change" git push -u origin feat/your-feature-name -# Open a Pull Request on GitHub +# Open a Pull Request with base = release/v3.8.49 ``` ### Branch Naming diff --git a/README.md b/README.md index f30bf34d7d..b0d070df0a 100644 --- a/README.md +++ b/README.md @@ -752,7 +752,7 @@ same process on one port, so there is no separate CLI-only package today. - 🌍 **Website**: [omniroute.online](https://omniroute.online) - 🐙 **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute) - 🐛 **Issues**: [report a bug](https://github.com/diegosouzapw/OmniRoute/issues) (attach `npm run system-info` output) -- 🤝 **Contributing**: see [CONTRIBUTING.md](CONTRIBUTING.md) or pick a `good first issue` +- 🤝 **Contributing**: see [CONTRIBUTING.md](CONTRIBUTING.md), [Branching & Release Model](docs/ops/BRANCHING_MODEL.md), or pick a `good first issue` @@ -846,6 +846,7 @@ same process on one port, so there is no separate CLI-only package today. | Document | Description                                                                                                                                                                              | | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [Contributing](CONTRIBUTING.md) | Development setup and guidelines | +| [Branching & Release Model](docs/ops/BRANCHING_MODEL.md) | Where PRs target (`release/*`), what `main` and tags mean | | [Changelog](CHANGELOG.md) | Full per-version release history | | [Security Policy](SECURITY.md) | Vulnerability reporting and security practices | | [i18n Guide](docs/guides/I18N.md) | 40+ language support, translation workflow, RTL | @@ -966,10 +967,11 @@ same process on one port, so there is no separate CLI-only package today. ### How to Contribute 1. Fork the repository -2. Create your feature branch (`git checkout -b feature/amazing-feature`) -3. Commit your changes (`git commit -m 'Add amazing feature'`) -4. Push to the branch (`git push origin feature/amazing-feature`) -5. Open a Pull Request +2. Branch from the **active** `release/vX.Y.Z` tip (not `main`) — see [Branching & Release Model](docs/ops/BRANCHING_MODEL.md) +3. Create your feature branch (`git checkout -b feat/amazing-feature`) +4. Commit your changes (`git commit -m 'feat: add amazing feature'`) +5. Push to the branch (`git push origin feat/amazing-feature`) +6. Open a Pull Request with **base = that `release/vX.Y.Z` branch** See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines. diff --git a/changelog.d/maintenance/7627-branching-model-doc.md b/changelog.d/maintenance/7627-branching-model-doc.md new file mode 100644 index 0000000000..340834d308 --- /dev/null +++ b/changelog.d/maintenance/7627-branching-model-doc.md @@ -0,0 +1 @@ +- **docs(ops):** publish public branching/release model (`release/*` = active cycle, `main` = published line, tag = ship marker) ([#7627](https://github.com/diegosouzapw/OmniRoute/issues/7627)) — thanks @c4usal diff --git a/docs/ops/BRANCHING_MODEL.md b/docs/ops/BRANCHING_MODEL.md new file mode 100644 index 0000000000..2d1e5a38a6 --- /dev/null +++ b/docs/ops/BRANCHING_MODEL.md @@ -0,0 +1,82 @@ +--- +title: "Branching & Release Model" +lastUpdated: 2026-07-22 +--- + +# Branching & Release Model + +OmniRoute uses a **parallel-cycle** release model: a dedicated `release/vX.Y.Z` +branch for the active cycle, `main` for the published line, and an immutable +`vX.Y.Z` tag when that cycle ships. Seeing commits land on `release/*` *and* on +`main` is expected — not a mix-up. + +Maintainer detail lives in `CLAUDE.md` (Hard Rule #21) and +[RELEASE_CHECKLIST.md](./RELEASE_CHECKLIST.md). This page is the public +contributor-facing summary. + +## At a glance + +| Ref | Role | +| --- | --- | +| `release/vX.Y.Z` | **Active cycle** — day-to-day development and PR merges for that version | +| `main` | **Published line** — receives the cycle via squash-merge when the release ships | +| `vX.Y.Z` (tag) | **Ship marker** — immutable “what shipped” pointer cut at release time | + +```mermaid +flowchart LR + A["feat/fix branch"] --> B["PR → release/vX.Y.Z"] + B --> C["release/vX.Y.Z tip"] + C --> D["Release PR squash-merges → main"] + D --> E["Tag vX.Y.Z"] + C --> F["Next cycle: release/vX+1 cut from frozen tip"] +``` + +## Where should my PR target? + +**Target the active `release/vX.Y.Z` branch — not `main`.** + +1. Find the highest open `release/v*` branch (example at the time of writing: + `release/v3.8.49`). +2. Branch from that tip (`git fetch` + checkout / rebase onto it). +3. Open the PR with **base = that `release/vX.Y.Z`**. + +`main` is not the day-to-day integration branch. PRs opened against `main` +usually need retargeting before merge. + +## Release freeze (parallel cycles) + +When a release is being reconciled, a marker issue labeled `release-freeze` is +opened. That **does not stop development**: + +- The frozen `release/vX.Y.Z` belongs to the release captain for that ship. +- The next cycle’s `release/vX+1` is cut from the frozen tip so contributors keep + landing work. +- Open PRs that still target the frozen branch should be **retargeted** to the + active (highest) `release/v*` branch. + +Check for an open freeze before assuming the branch you want is mergeable: + +```bash +gh issue list --repo diegosouzapw/OmniRoute --label release-freeze --state open +``` + +Merge mechanics (owner `queue` label → Mergify) are documented in +[MERGE_TRAIN.md](./MERGE_TRAIN.md). + +## Why both a branch and a tag? + +| Artifact | Lifetime | Purpose | +| -------- | -------- | ------- | +| `release/vX.Y.Z` | In-flight cycle | Collects reviewed PRs, stays CI-green, is the PR base | +| Tag `vX.Y.Z` | Forever | Marks the exact bits that shipped to npm / GitHub Releases | + +The branch is the workshop; the tag is the sealed package. After squash-merge to +`main`, the next cycle continues on `release/vX+1` without waiting for the prior +release PR to finish. + +## Related docs + +- [CONTRIBUTING.md](../../CONTRIBUTING.md) — setup, tests, PR checklist +- [RELEASE_CHECKLIST.md](./RELEASE_CHECKLIST.md) — pre-ship validation +- [MERGE_TRAIN.md](./MERGE_TRAIN.md) — merge queue and fallback train +- [RELEASE_GREEN.md](./RELEASE_GREEN.md) — keeping the release tip green