--- name: development-workflow description: Use when choosing a branching strategy, writing a commit message, opening or reviewing a pull request, setting up commit linting, or tagging a versioned release. --- # Development Workflow A complete reference for Git branching, commit conventions, pull request workflow, code review practices, and release management — covering everything from first branch to published release. ## When to Activate - Starting work on a new feature, bug fix, or chore - Writing a commit message - Opening or reviewing a pull request - Deciding on a branching strategy for a new project or team - Creating a release or version tag - Setting up commit message linting or changelog generation ## Branching Strategies ### Comparison Table | Strategy | Branches Used | Release Cadence | Team Size Fit | Pros | Cons | |---|---|---|---|---|---| | **GitHub Flow** | `main` + feature branches | Continuous (deploy on merge) | Small–medium | Simple, fast feedback, CD-friendly | No built-in release staging | | **Git Flow** | `main`, `develop`, `feature/*`, `release/*`, `hotfix/*` | Scheduled / versioned | Medium–large | Clear release lifecycle, hotfix path | Complex, slow merging, overhead | | **Trunk-Based Development** | `main` (+ very short-lived branches) | Continuous | Any (with CI maturity) | Maximum integration speed, minimal merge conflicts | Requires feature flags, strong CI discipline | ### GitHub Flow Developers branch from `main`, open a pull request, and merge back to `main` on approval. Merging to `main` triggers deployment. Suitable when every merged commit should ship. ```bash git checkout -b feat/PROJ-42-add-oauth main # ... commit work ... git push -u origin feat/PROJ-42-add-oauth # Open PR → review → merge → auto-deploy ``` ### Git Flow Use when releases are batched on a schedule (e.g., sprint releases, versioned libraries). ```bash # New feature git checkout -b feature/PROJ-99-dark-mode develop # Prepare a release git checkout -b release/1.4.0 develop # bump version, final fixes, then merge to main AND develop git checkout main && git merge release/1.4.0 git tag -a v1.4.0 -m "Release v1.4.0" # Emergency hotfix git checkout -b hotfix/fix-login-crash main # fix, then merge to main AND develop ``` ### Trunk-Based Development All engineers commit to `main` (or merge very short-lived branches within a day or two). Unfinished work is hidden behind feature flags. ```bash # Short-lived branch — merged same day or next git checkout -b fix/null-check-cart git commit -m "fix(cart): guard against null item list" git push && gh pr create --fill ``` ### Decision Guide - **Deploy on every merge (CD pipeline)** → GitHub Flow or Trunk-Based Development - **Scheduled release trains / versioned artifacts** → Git Flow - **Maximum integration speed, mature CI, feature-flag infrastructure** → Trunk-Based Development ## Branch Naming Pattern: `/-` | Type | Example | |---|---| | `feat` | `feat/PROJ-123-user-auth` | | `fix` | `fix/login-null-pointer` | | `chore` | `chore/update-deps` | | `docs` | `docs/api-readme` | | `refactor` | `refactor/PROJ-200-extract-service` | Rules: - Lowercase letters and hyphens only — no underscores or slashes in the description segment - Include a ticket reference where one exists - Keep total length under 50 characters - No personal identifiers (no `johns-branch`) ## Conventional Commits ### Commit Type Reference | Type | Meaning | Changelog / Version Effect | |---|---|---| | `feat` | New feature | Minor version bump | | `fix` | Bug fix | Patch version bump | | `docs` | Documentation only | No bump | | `style` | Formatting, whitespace — no logic change | No bump | | `refactor` | Code restructure, no feature or fix | No bump | | `perf` | Performance improvement | Patch version bump | | `test` | Tests only | No bump | | `chore` | Build scripts, tooling, dependencies | No bump | | `ci` | CI/CD configuration changes | No bump | | `build` | Build system or external dependency changes | No bump | | `revert` | Reverts a prior commit | Depends on reverted commit | ### Breaking Changes Add `!` after the type to signal a breaking change, or add a `BREAKING CHANGE:` footer in the commit body. ```bash feat!: remove legacy v1 authentication endpoint BREAKING CHANGE: The /api/v1/auth endpoint has been removed. Clients must migrate to /api/v2/auth before upgrading. ``` ### Scope Optional. Place in parentheses between type and colon. ``` feat(auth): add refresh token rotation fix(cart): prevent duplicate item insertion chore(deps): upgrade eslint to v9 ``` ### BAD / GOOD Example ```bash # BAD — vague, no type, no scope, doesn't explain impact git commit -m "fix stuff" # GOOD — type, scope, imperative mood, explains what changed git commit -m "fix(auth): resolve null pointer when session token is missing" ``` ## Pull Request Workflow ### PR Description Template ```markdown ## What [one paragraph: what changed — be specific about files, components, or APIs affected] ## Why [one paragraph: why this change is needed; link to ticket or issue] ## How [optional: explain non-obvious implementation decisions or trade-offs] ## Testing - [ ] Unit tests added/updated - [ ] Integration tests pass - [ ] Tested manually: [describe steps and environment] ## Screenshots / Demo [if UI change — include before/after screenshots or a short screen recording] ``` ### Draft PRs Open as a draft (`gh pr create --draft`) when the branch is in progress and early feedback is wanted. Convert to ready-for-review once CI is green and the description is complete. ```bash gh pr create --draft --title "feat(auth): add OAuth2 PKCE flow" --body "$(cat pr-body.md)" gh pr ready # convert to ready ``` ### Linking Issues ``` Closes #123 # closes the issue on merge Fixes #456 # alias for Closes Relates to #789 # reference without auto-closing ``` ### PR Size Target under 400 LOC of production code per PR. Large changes should be split into stacked PRs where each PR builds on the previous and can be reviewed independently. ### Merge Strategies | Strategy | History Shape | When to Use | |---|---|---| | **Squash merge** | One commit per feature branch | Clean main history; preferred for most feature branches | | **Merge commit** | Full branch history preserved | When branch history is meaningful (e.g., a spike or investigation) | | **Rebase merge** | Linear, no merge commits | When team values perfectly linear history and all commits are high quality | Pick one strategy per repository and enforce it consistently. GitHub allows disabling unwanted strategies under repository settings. ## Code Review Practice ### Reviewer Responsibilities Reviewers check for: correctness, test coverage, security implications, performance concerns, naming clarity, and API design consistency. Checking formatting is the job of the linter, not the reviewer. ### Feedback Labels Prefix review comments to signal urgency and type: | Prefix | Meaning | Blocking? | |---|---|---| | `nit:` | Style or preference, minor polish | No | | `suggestion:` | A better approach exists; author's call | No | | `question:` | Seeking clarification or understanding | No | | `request:` | Must be addressed before approval | Yes | ### Giving Feedback - Be specific: reference the exact line or pattern, not a general feeling. - Explain why: link to a doc, standard, or reason — not just "change this." - Suggest an alternative: show what you'd prefer, don't just flag the problem. - Don't be personal: comment on the code, not the author. ```markdown # BAD This is wrong. # GOOD request: `userId` can be null here if the session has expired. Suggest adding a null guard before the lookup: `if (!userId) return res.status(401).json({ error: 'Unauthorized' });` ``` ### Receiving Feedback - Separate ego from code — the review is about quality, not judgment. - Ask for clarification before defending: "Can you say more about why X is preferred here?" - Address every comment, even if just to acknowledge it: "Acknowledged — leaving as-is because [reason]." - Avoid drive-by rewrites; if a comment sparks a bigger refactor, open a follow-up ticket. ### Author Checklist Before Requesting Review - Self-review the diff in GitHub/GitLab before submitting — read your own code as if you were the reviewer. - PR description is complete: What, Why, How, Testing. - CI is green. - No debug code, `console.log`, or commented-out blocks remain. - No unresolved merge conflicts. ## Release Tagging and Semantic Versioning ### SemVer Rules Format: `MAJOR.MINOR.PATCH` | Segment | Increment When | |---|---| | `MAJOR` | Breaking change — existing callers must update | | `MINOR` | New backward-compatible feature added | | `PATCH` | Backward-compatible bug fix | Pre-release labels: `1.0.0-alpha.1`, `2.3.0-rc.2` Build metadata (ignored in precedence): `1.0.0+20240102` ### Creating Annotated Tags ```bash # Annotated tag — preferred for releases (stores tagger, date, message) git tag -a v1.2.3 -m "Release v1.2.3" git push origin v1.2.3 # List tags git tag -l "v*" # Delete a mistaken tag (locally and remotely) git tag -d v1.2.3 git push origin --delete v1.2.3 ``` ### CHANGELOG Maintain a `CHANGELOG.md` in [Keep a Changelog](https://keepachangelog.com) format with sections `Added`, `Changed`, `Deprecated`, `Removed`, `Fixed`, `Security`. ```markdown ## [1.2.3] - 2026-04-02 ### Fixed - Resolve null pointer in session validation (#456) ## [1.2.0] - 2026-03-15 ### Added - OAuth2 PKCE authentication flow (#399) ``` ### Automation Tools | Tool | Approach | Notes | |---|---|---| | `semantic-release` | Fully automated — reads commits, bumps version, publishes, creates GitHub release | Zero-touch; requires strict Conventional Commits discipline | | `release-please` (Google) | Creates a "Release PR" with changelog and version bump; engineer merges to ship | Semi-automated; good for teams that want a human gate before release | | `standard-version` (deprecated) | Local CLI, generates changelog and tag | Superseded by `release-please` / `semantic-release` | ## Red Flags - **Long-lived feature branches (more than a week)** — diverging from `main` for days accumulates merge conflicts and delays integration feedback; split the work into smaller increments or use feature flags - **Commit messages in past tense or with no type prefix** — "Fixed the login bug" makes automated changelog generation and `git bisect` harder; use the imperative form with a Conventional Commits type: `fix(auth): guard against null session token` - **PR with 1,000+ LOC that mixes refactoring and feature work** — reviewers cannot reason about two concerns simultaneously; split into a refactoring PR (no behavior change) and a feature PR on top - **Force-pushing to a shared branch** — rewriting history that colleagues have already pulled causes divergent histories and lost commits; never force-push to `main` or a shared branch; use a new commit to amend - **Squash-merging without updating the PR description** — the squash commit message defaults to the PR title only; the description (Why, How) is lost from git history where it would be most valuable for `git log` - **Merging without a required CI green check** — bypassing status checks to "unblock" is the single most common source of regressions on `main`; enforce required status checks in branch protection settings - **Using lightweight tags for releases instead of annotated tags** — lightweight tags have no author, date, or message; `git tag -a v1.2.3 -m "..."` is required for `git describe` and release tooling to work correctly - **No `CHANGELOG.md` entry on release** — a tag with no changelog forces the next developer to read raw `git log` to understand what changed; automate with `semantic-release` or `release-please` ## Checklist - [ ] Branch name follows `/-` convention - [ ] All commits follow Conventional Commits spec (type, optional scope, imperative subject) - [ ] Breaking changes marked with `!` or `BREAKING CHANGE:` footer - [ ] PR description filled out (What / Why / How / Testing sections complete) - [ ] PR is under 400 LOC of production code, or split into stacked PRs - [ ] CI is green before requesting review - [ ] No debug code, `console.log`, or commented-out blocks left in - [ ] Issues linked with `Closes #` or `Fixes #` where applicable - [ ] Reviewer feedback addressed or explicitly acknowledged before merge - [ ] Merge strategy matches team convention (squash / merge commit / rebase) - [ ] Release tagged with annotated tag following SemVer (`git tag -a vX.Y.Z`) - [ ] CHANGELOG updated or auto-generated via `semantic-release` / `release-please`