ADR-002: Git branching model
- Status: Superseded by ADR-007
- Date: 2026-10-10
Context
Projects range from solo repositories to open-source work with external contributors. They need an integration branch, a deliberate release gate, and traceable history, with no paid tooling. An earlier project ADR chose dev plus main, merge commits, Conventional Commits, and tag-based deploys, with 1 approval into dev and 2 into main. Other guidance asks only for pull requests without mandatory approvals, which is the realistic setting for a solo maintainer.
Decision
- Two permanent branches:
dev(integration) andmain(production candidates). All changes arrive through pull requests; nobody commits or pushes directly to either. - Short-lived
feature/*,fix/*,chore/*branches targetdev;hotfix/*targetsmain. - Pull requests merge with a merge commit, never squash or rebase.
- Commits follow Conventional Commits.
- A
vX.Y.Ztag onmaintriggers production deployment. - Approvals: a pull request and passing CI are always required. Human approvals are required only when more than one person contributes (1 into
dev, 2 intomain); solo repositories use zero. - Commit messages carry no AI or tool co-author trailers.
Consequences
Positive
devabsorbs churn before it reaches production, and a tag is a deliberate release gate.- Merge commits preserve feature history, make a single revert possible, and let
devfast-forward after a release. - The approval rule scales from solo work to a team without a separate process.
Negative
- Promoting
devtomainadds a step compared with trunk-based development. - Merge commits make history noisier than squash or rebase.
devmust be back-synced frommainafter each release.- Without co-author trailers, AI involvement is not visible in
git log; the pull request description is where it can be noted.
Alternatives Considered
- Squash merge
- Why it was considered: linear history.
- Why it was not selected: loses intermediate commits and breaks the
devfast-forward back-sync.
- Rebase merge
- Why it was considered: linear history without merge commits.
- Why it was not selected: rewrites SHAs and is harder for occasional contributors.
- Trunk-based development on
main- Why it was considered: simplest model.
- Why it was not selected: no integration branch and no gate between merge and production.