From 1fa2d083cc63383fd04741463f99957489106e68 Mon Sep 17 00:00:00 2001 From: Parth Detroja Date: Mon, 8 Jun 2026 15:24:46 +0530 Subject: [PATCH] docs(branching): add branching strategy and update CONTRIBUTING MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - New BRANCHING.md documenting the two-branch model (main + staging), 11 topic-branch types, PR/hotfix/release workflows, protected branch rules, and ready-to-run gh api commands for enabling them - Fix CONTRIBUTING.md base branch (main -> staging) and update branch naming examples to Conventional-Commits style - Add BRANCHING.md to .claude/REFERENCES.md docs index Step 2 of the open-source repo maintenance baseline initiative. Branch protection rules are documented in BRANCHING.md but NOT applied to GitHub yet — they will be enabled after this PR merges to avoid blocking the very PR that introduces them. Co-Authored-By: Claude Opus 4.7 --- .claude/REFERENCES.md | 1 + BRANCHING.md | 327 ++++++++++++++++++++++++++++++++++++++++++ CONTRIBUTING.md | 23 +-- 3 files changed, 342 insertions(+), 9 deletions(-) create mode 100644 BRANCHING.md diff --git a/.claude/REFERENCES.md b/.claude/REFERENCES.md index 54568e4..f0d6d23 100644 --- a/.claude/REFERENCES.md +++ b/.claude/REFERENCES.md @@ -17,6 +17,7 @@ | Resource | Path | Purpose | |----------|------|---------| | **Contributing Guide** | [CONTRIBUTING.md](../../CONTRIBUTING.md) | How to contribute | +| **Branching Strategy** | [BRANCHING.md](../../BRANCHING.md) | Branch model, PR/hotfix/release workflows | | **Security Policy** | [SECURITY.md](../../SECURITY.md) | Report security vulnerabilities | | **Code of Conduct** | [CODE_OF_CONDUCT.md](../../CODE_OF_CONDUCT.md) | Community standards | | **License** | [LICENSE](../../LICENSE) | MIT open-source license | diff --git a/BRANCHING.md b/BRANCHING.md new file mode 100644 index 0000000..c029287 --- /dev/null +++ b/BRANCHING.md @@ -0,0 +1,327 @@ +# Branching Strategy + +AlianHub uses a **two-branch model** with a clear separation between stable releases and active development. This guide documents how branches flow, what each branch is for, and how contributors should work with them. + +--- + +## TL;DR + +| Branch | Purpose | Stability | Direct push? | +|---|---|---|---| +| `main` | Stable, public-facing | Production-ready | ❌ PR + review only | +| `staging` | Active development | Pre-release | ❌ PR + CI only | +| `/` | Feature / fix / chore branches | Work in progress | ✅ Your branch | + +- **Internal contributors** → branch off `staging` → PR back to `staging` +- **External contributors** → fork → branch off `staging` → PR back to `staging` +- **Production hotfixes** → branch off `main` → PR to `main` → backport to `staging` + +--- + +## Branch flow + +``` + ┌─────────────────┐ + │ main │ ◄── stable, production, tagged releases + │ (protected) │ + └────────▲────────┘ + │ promoted at release time + │ + ┌────────┴────────┐ + │ staging │ ◄── active development (base for all work) + │ (protected) │ + └────────▲────────┘ + │ PRs from topic branches + ┌────────────┼────────────┐ + │ │ │ + feat/widget fix/login-bug chore/cleanup + (your work) (your work) (your work) +``` + +--- + +## Long-running branches + +### `main` +- The **stable**, public-facing branch. +- Every commit on `main` corresponds to a **tagged release** (`v14.x.x`). +- Updated only by: + - Promotion (merge) from `staging` at release time, **or** + - `hotfix/*` PRs for urgent production fixes. +- **Never** push directly to `main`. +- Protected: requires PR + 1 approving review + green CI + linear history. + +### `staging` +- The **active development** branch — the base for all new work. +- All `feat/`, `fix/`, `refactor/`, `chore/`, `docs/`, `perf/`, `test/`, `ci/`, `build/`, `style/` PRs target `staging`. +- Should always be deployable to the demo / staging environment. +- Protected: requires PR + green CI. Maintainers can self-merge (no second reviewer required), but force-push is blocked. + +--- + +## Topic branches + +All work happens on short-lived **topic branches** that target `staging` (or `main` for hotfixes). + +### Naming convention + +``` +/ +``` + +| Type | Use for | Example | +|---|---|---| +| `feat/` | New features | `feat/employee-workload-report-widget` | +| `fix/` | Bug fixes | `fix/login-validation-error` | +| `hotfix/` | Urgent production fixes (branch from `main`) | `hotfix/payment-gateway-timeout` | +| `refactor/` | Code refactoring (no behavior change) | `refactor/auth-helper-extract` | +| `chore/` | Build, config, license, deps | `chore/relicense-to-agpl-3.0` | +| `docs/` | Documentation only | `docs/branching-strategy` | +| `perf/` | Performance improvements | `perf/task-list-query` | +| `test/` | Adding or fixing tests | `test/auth-helper-coverage` | +| `ci/` | CI configuration changes | `ci/add-release-workflow` | +| `build/` | Build system changes | `build/upgrade-webpack` | +| `style/` | Formatting only | `style/prettier-config` | + +> Keep descriptions short, kebab-case, and informative. Avoid issue numbers in the branch name — link them in the PR description instead. + +### Lifecycle + +1. **Create** from the latest `staging`: + ```bash + git checkout staging + git pull + git checkout -b feat/your-feature + ``` +2. **Commit** following [Conventional Commits](https://www.conventionalcommits.org/) (see PR & branch name formats — coming in step 3 of the OSS baseline). +3. **Push** with upstream tracking: + ```bash + git push -u origin feat/your-feature + ``` +4. **Open PR** targeting `staging` (or `main` for hotfixes). +5. **Delete** the branch after merge (GitHub auto-deletes on merge if enabled in repo settings). + +--- + +## Pull Request workflow + +### Where do PRs target? + +| Branch type | PR base | +|---|---| +| `feat/`, `fix/`, `refactor/`, `chore/`, `docs/`, `perf/`, `test/`, `ci/`, `build/`, `style/` | `staging` | +| `hotfix/` | `main` (and backported to `staging` after merge) | +| `release/v*` | `main` (cut from `staging`) | + +### Requirements (enforced via branch protection) + +**For PRs into `main`:** +- ✅ 1 maintainer approval required +- ✅ All CI checks passing +- ✅ No merge conflicts +- ✅ Conventional Commit format in PR title +- ✅ Linear history (squash or rebase merge only) +- ✅ Conversation resolution required + +**For PRs into `staging`:** +- ✅ All CI checks passing +- ✅ No merge conflicts +- ✅ Conventional Commit format in PR title +- 🟡 Self-merge allowed for maintainers (no required reviewer) + +--- + +## Hotfix workflow + +For urgent production bugs that can't wait for the next `staging → main` promotion: + +1. Branch from `main`: + ```bash + git checkout main + git pull + git checkout -b hotfix/short-description + ``` +2. Fix, commit, push. Open PR **targeting `main`**. +3. After review and merge, backport to `staging`: + ```bash + git checkout staging + git pull + git cherry-pick + git push + ``` + *(Or open a separate `hotfix-backport/` PR → `staging`.)* +4. Tag a patch release on `main` (e.g., `v14.0.27` → `v14.0.28`). + +--- + +## Release workflow (`staging` → `main`) + +Releases happen **on demand** when `staging` is stable and ready to ship. There is no fixed cadence — release when there is meaningful value to ship (typically every 1–4 weeks). + +### Steps + +1. Verify all PRs intended for the release are merged into `staging`. +2. Verify CI is green on `staging` HEAD. +3. Open a release PR: branch `release/v14.x.x` from `staging`, target `main`. + - PR body: a changelog of all merged PRs since the last release. +4. After approval and CI pass, **merge** the release PR into `main`. +5. Tag the release on `main`: + ```bash + git checkout main + git pull + git tag -a v14.x.x -m "Release v14.x.x" + git push origin v14.x.x + ``` +6. A GitHub Release is created automatically by release tooling (see step 4 of the OSS baseline — `release-please`). Until that's set up, create the Release manually with the same changelog body. + +> 💡 This whole flow will be automated via `release-please` in step 4 of the open-source repo maintenance baseline initiative. + +--- + +## External contributors + +External contributors do **not** have push access to the upstream repo. The workflow is fork-based: + +1. **Fork** the repo on GitHub. +2. **Clone** your fork: + ```bash + git clone https://github.com//AlianHub-Project-Management-System.git + cd AlianHub-Project-Management-System + git remote add upstream https://github.com/aliansoftwareteam/AlianHub-Project-Management-System.git + ``` +3. **Sync** your fork's `staging` with upstream: + ```bash + git fetch upstream + git checkout staging + git merge upstream/staging + git push origin staging + ``` +4. **Branch** off `staging`: + ```bash + git checkout -b feat/your-feature + ``` +5. **Commit, push, open PR** from your fork's branch → upstream's `staging`. + +--- + +## Protected branch rules + +The following rules are enforced via GitHub branch protection. Admins should not bypass these except in genuine emergencies (and document the override in the next commit). + +### `main` +- ❌ Direct pushes blocked +- ❌ Force push blocked +- ❌ Branch deletion blocked +- ✅ PR required +- ✅ 1 approving review required +- ✅ All status checks must pass +- ✅ Branches must be up to date before merging +- ✅ Linear history required (squash or rebase merge only) +- ✅ Conversation resolution required + +### `staging` +- ❌ Direct pushes blocked (maintainers must use PRs) +- ❌ Force push blocked +- ❌ Branch deletion blocked +- ✅ PR required +- ✅ All status checks must pass +- 🟡 No required reviewer (maintainer self-merge OK) + +--- + +## How to enable branch protection (one-time setup) + +Run these from a terminal with the GitHub CLI (`gh`) authenticated as a repo admin: + +```bash +# main: require PR + 1 review + status checks + linear history +gh api -X PUT repos/aliansoftwareteam/AlianHub-Project-Management-System/branches/main/protection \ + --input - <<'EOF' +{ + "required_status_checks": { "strict": true, "contexts": [] }, + "enforce_admins": false, + "required_pull_request_reviews": { + "required_approving_review_count": 1, + "dismiss_stale_reviews": true + }, + "restrictions": null, + "required_linear_history": true, + "allow_force_pushes": false, + "allow_deletions": false, + "required_conversation_resolution": true +} +EOF + +# staging: require PR + status checks, no required reviewer +gh api -X PUT repos/aliansoftwareteam/AlianHub-Project-Management-System/branches/staging/protection \ + --input - <<'EOF' +{ + "required_status_checks": { "strict": true, "contexts": [] }, + "enforce_admins": false, + "required_pull_request_reviews": { + "required_approving_review_count": 0, + "dismiss_stale_reviews": false + }, + "restrictions": null, + "required_linear_history": false, + "allow_force_pushes": false, + "allow_deletions": false +} +EOF +``` + +After step 4 (release process) sets up CI, populate `required_status_checks.contexts` with the actual check names (e.g., `["build", "test", "lint"]`). + +--- + +## Cheatsheet + +```bash +# Start a new feature +git checkout staging && git pull +git checkout -b feat/your-feature-name + +# Start a hotfix +git checkout main && git pull +git checkout -b hotfix/your-fix-name + +# Sync your branch with the latest staging (preferred: rebase) +git fetch origin +git rebase origin/staging + +# Push and open PR +git push -u origin feat/your-feature-name +gh pr create --base staging --fill + +# After merge, clean up local branch +git checkout staging && git pull +git branch -d feat/your-feature-name +``` + +--- + +## FAQ + +**Q: Why two branches instead of GitHub Flow (just `main`)?** +A: AlianHub is a self-hosted product with paying users. We need a stable branch that represents "what is in production" separate from "what is being worked on." `main` = released, `staging` = pre-release. + +**Q: Why not GitFlow with `develop`?** +A: GitFlow's `develop`/`release`/`master` triple is over-engineered for a single-repo product. Two branches give us the same safety with half the ceremony. + +**Q: Can I merge directly to `main` to skip the staging step?** +A: No. Only `hotfix/*` and `release/v*` branches target `main`. Everything else goes through `staging` first so it's been deployed to the demo environment and exercised. + +**Q: How often is `staging` promoted to `main`?** +A: On demand, when there's meaningful value to ship. Typically every 1–4 weeks. Maintainers decide. + +**Q: What if my PR has been sitting in `staging` for weeks and now conflicts with `main`?** +A: Rebase your branch onto the latest `staging`, resolve conflicts, force-push your branch (allowed on your own topic branch — only `main`/`staging` block force-pushes), and re-request review. + +--- + +## See Also + +- [CONTRIBUTING.md](CONTRIBUTING.md) — Contribution guidelines +- [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) — Community standards +- [SECURITY.md](SECURITY.md) — Security reporting policy +- Plane's reference: https://github.com/makeplane/plane (uses `master` + `preview` — same two-branch idea, different names) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2059679..d6ae9da 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,21 +19,26 @@ Please read this guide carefully before submitting issues or pull requests. - Be open to feedback and discussion ### 3. Submitting Pull Requests -- Fork the repository -- Create a feature branch from the latest `main` +- Fork the repository (external contributors) or branch directly (maintainers) +- Create a topic branch from the latest `staging` — **not** `main` - Keep changes focused and minimal -- Use the appropriate PR template: - - `new_feature.md` - - `bug_fix.md` - - `refactor.md` +- Open the PR against `staging` (not `main`) + +> 📘 See [BRANCHING.md](BRANCHING.md) for the full branching strategy, including hotfix and release workflows. ## Branch Naming Convention -Examples: -- `feature/user-notifications` -- `bugfix/login-validation` +Use the format `/`: + +- `feat/user-notifications` +- `fix/login-validation` - `refactor/api-layer` +- `chore/upgrade-deps` +- `docs/api-reference` +- `hotfix/payment-gateway-timeout` *(branched from `main`, not `staging`)* + +Full list of accepted types and examples: [BRANCHING.md § Topic branches](BRANCHING.md#topic-branches). ## Testing Requirements