Skip to content
Developer Template5 columns · 5 sample rows· Updated

Git Workflow & Branching Governance Markdown Table Template

A branching table turns a team’s Git workflow from tribal knowledge into rules a contributor can follow on their first day. For each branch pattern it states where the branch starts, where its work ends up, who has to approve the merge, and which automated checks must pass first. It usually lives in CONTRIBUTING.md or the engineering handbook, and it is the document people open when they are unsure whether a fix goes against develop or main.

Edit This Template

Edit cells, add rows, or sort — the Markdown updates live
Row
1
main
2
develop
main
3
feature/*
develop
develop
4
hotfix/*
main
main & develop
5
release/*
develop
main & develop
Output
| Branch Name | Base Source | Merge Target       | Required Approvals | CI Automation Gates                            |
| :---------- | :---------- | :----------------- | :----------------: | :--------------------------------------------- |
| `main`      | —           | Production Deploy  | 2 Senior Engineers | Full E2E suite, Semgrep, build validation      |
| `develop`   | `main`      | Staging Deploy     |  1 Peer Reviewer   | Unit tests, TypeScript typecheck, linter       |
| `feature/*` | `develop`   | `develop`          |  1 Peer Reviewer   | Fast unit tests, branch conflict check         |
| `hotfix/*`  | `main`      | `main` & `develop` |    1 Tech Lead     | Targeted regression test, immediate deployment |
| `release/*` | `develop`   | `main` & `develop` | 1 Release Manager  | Changelog verification, version tag generation |
5 rows × 5 columns
Rendered Preview
Branch NameBase SourceMerge TargetRequired ApprovalsCI Automation Gates
main—Production Deploy2 Senior EngineersFull E2E suite, Semgrep, build validation
developmainStaging Deploy1 Peer ReviewerUnit tests, TypeScript typecheck, linter
feature/*developdevelop1 Peer ReviewerFast unit tests, branch conflict check
hotfix/*mainmain & develop1 Tech LeadTargeted regression test, immediate deployment
release/*developmain & develop1 Release ManagerChangelog verification, version tag generation

When to Use This Table

The table is read at decision points: a developer creating a branch for an urgent production bug, a reviewer wondering whether one approval is enough, a release manager cutting a version, a new hire whose pull request was blocked by a check they have never heard of. It also doubles as the specification for the repository settings, since every row should correspond to a branch protection rule or ruleset that enforces it.

A useful table matches one coherent model. The template describes Git Flow — long-lived main and develop, plus feature/*, release/*, and hotfix/* — which suits software shipped as numbered versions with more than one release in support. Teams that deploy a single web app continuously usually do better with trunk-based development or GitHub flow, and Vincent Driessen, who described Git Flow in 2010, added a note in 2020 saying as much. The weak version of this table mixes models, or describes rules that the repository does not enforce.

What Goes in Each Column

ColumnAlignmentWhat to put here
Branch Nameleft :---The branch or pattern in backticks: main, feature/*. On GitHub, patterns use fnmatch syntax in which * does not cross a slash, so feature/* misses feature/payments/refunds; add feature/*/* as a second pattern if nested names are allowed, or use a double-asterisk pattern, which matches any depth. Long-lived branches first, then short-lived ones.
Base Sourceleft :---The branch this one is created from. Short-lived branches always have one: features from develop, hotfixes from main. Long-lived branches are created once, so write — for main and main for develop, and describe what flows into them under Merge Target of the other rows.
Merge Targetleft :---Where the finished branch merges, plus any back-merge. In Git Flow, release/* and hotfix/* both go to main and back to develop, otherwise the fix disappears in the next release. For long-lived branches, describe what the branch triggers, such as a production or staging deploy.
Required Approvalscenter :---:A number plus who counts, matched to something the platform can enforce: “2, including a code owner” maps directly to the required-approvals setting plus CODEOWNERS. Seniority labels like “senior engineer” only hold if a CODEOWNERS team encodes them. Centered because readers compare the counts down the column.
CI Automation Gatesleft :---The checks that must be green before merging, named exactly as they appear in the pull request’s checks list, because required status checks match on that name. Mention post-merge automation separately, since a deploy that runs after merging is not a gate.

How to Fill It In

  1. 1Choose the model before writing rows. If you deploy one version continuously, start from trunk-based development or GitHub flow; if customers run several released versions that you patch, Git Flow or maintained release branches fit better.
  2. 2Write one row per branch or pattern and check every pattern against real branch names with git branch -r --list 'origin/feature/*'.
  3. 3Copy check names from a recent pull request’s checks tab, not from the workflow file’s file name. Renaming a CI job without updating the protection rule leaves every pull request stuck waiting for a check that will never report.
  4. 4Enforce each row in the platform: on GitHub, a ruleset or branch protection rule with the approval count, Code Owners review, required status checks, and blocked force pushes. Note who is on the bypass list.
  5. 5Test the rules with a throwaway pull request that fails a check and has too few approvals, and confirm it cannot merge.
  6. 6Link the table from CONTRIBUTING.md and from the pull request template so contributors meet it before they open a branch.

Ready-to-Paste Variations

Trunk-based development

For teams deploying from main continuously. Short-lived branches and feature flags replace develop and release/*.

| Branch | Created from | Merges into | Lifetime | Gates |
| :--- | :--- | :--- | :---: | :--- |
| `main` | — | Deploys to production on every merge | Permanent | Merge queue; full test suite |
| `<user>/<short-topic>` | `main` | `main` (squash) | Hours to 2 days | Lint, unit tests, 1 approval |
| `revert-*` | `main` | `main` | Minutes | Unit tests; 1 approval, any maintainer |

Maintained release branches

For libraries or on-premise products that patch several versions at once. Fixes land on main first and are cherry-picked backwards.

| Branch | Created from | Receives | Approvals | Gates |
| :--- | :--- | :--- | :---: | :--- |
| `main` | — | All feature work and fixes | 1 | Full test matrix |
| `release/3.x` | `main` at `v3.0.0` | Cherry-picked fixes only | 2 | Full test matrix, API compatibility check |
| `release/2.x` | `main` at `v2.0.0` | Security fixes only | 2, including security team | Full test matrix |

From policy to GitHub ruleset settings

Maps each policy column to the setting that enforces it, which is useful when auditing whether a repository matches its own documentation.

| Policy in the table | GitHub ruleset setting |
| :--- | :--- |
| Merge only through pull requests | Require a pull request before merging |
| 2 approvals, one from the owning team | Required approvals: 2, plus Require review from Code Owners |
| New commits need a fresh review | Dismiss stale pull request approvals when new commits are pushed |
| CI gates must pass | Require status checks to pass |
| No history rewriting | Block force pushes |

Common Mistakes

  • Listing develop as the base of main, or feature/* as the base of develop.

    Base Source is where a branch is created from. In Git Flow, develop is created from main once, and main only receives merges from release/* and hotfix/*. Show those flows in the Merge Target column of the short-lived branches.

  • Merging a release branch into main and stopping there.

    Merge release/* back into develop as well, or version bumps and last-minute fixes are lost. If a release branch is open when a hotfix lands, Git Flow merges the hotfix into that release branch instead of develop.

  • Writing approval rules the platform cannot check.

    “2 senior engineers” is a social rule unless a CODEOWNERS entry assigns those paths to a senior team and the ruleset requires Code Owners review. Write the enforceable version and keep the intent in a footnote.

  • Allowing feature branches to live for weeks.

    Long-lived branches turn into painful merges whichever model you use. Set a target lifetime, merge incomplete work behind a feature flag, and rebase or merge from the base branch daily.

Browse all 50 templates
FAQ

Git Workflow & Branching Governance: Frequently Asked Questions

Should we use Git Flow or trunk-based development?

Ask how many versions you support at once. A web service with one production version gets little from develop and release/* and pays for them in merge overhead. Mobile apps, desktop software, and libraries with supported older versions benefit from release branches.

Squash, merge commit, or rebase?

A common split is to squash feature branches so each pull request becomes one commit, and to use merge commits (--no-ff) for release and hotfix merges into main, so each release is a visible point in history. Pick per branch and record it in this table.

Do hotfixes need the same approvals as features?

Usually fewer approvers but the same checks. Speed should come from a smaller diff and a named on-call approver, not from skipping tests. If admins may bypass rules in an emergency, say so in the table and review every bypass afterwards.

How do I document branch naming beyond the prefix?

Add a line under the table with the full pattern and an example, such as feature/<ticket>-<slug> and feature/PAY-142-refund-api. Including the ticket key lets trackers such as Jira link the branch to its issue automatically.