name: git-best-practices
description: Enforces Git workflow best practices including trunk-based development, conventional commits, atomic commits, small pull requests, and Git hooks. Use when choosing a branching strategy, writing commit messages, structuring pull requests, configuring Git hooks and CI pipelines, managing feature flags, or setting up semantic versioning automation.
Git Best Practices
Reference: Pro Git (Chacon & Straub), Continuous Delivery (Humble & Farley), Accelerate (Forsgren et al.)
When to Apply
- Choosing or evaluating a branching strategy for a team or project
- Writing commit messages or reviewing them in pull requests
- Structuring pull requests for effective code review
- Setting up Git hooks and commit validation tooling
- Implementing automated versioning and changelog generation
- Improving DORA metrics (lead time, deployment frequency, change failure rate)
Branching Strategy
Trunk-Based Development (Recommended Default)
All developers collaborate on a single branch (trunk/main). Two variants:
| Variant |
Team Size |
Branch Lifetime |
Merge Method |
| Direct to trunk |
Small (≤5 developers) |
No branches |
Direct push |
| Short-lived feature branches |
Any size |
1–2 days maximum |
PR + merge |
- SHOULD default to trunk-based development — DORA research confirms higher-performing organizations are more likely to use TBD
- MUST keep feature branches to 1–2 days maximum; MUST NOT let branches live longer than a week
- MUST use feature flags to decouple deployment from release when features span multiple days
Branching Strategies Compared
| Strategy |
Best For |
Avoid When |
| Trunk-Based |
SaaS, continuous deployment, high-cadence teams |
N/A — suitable for most teams |
| GitHub Flow |
Simple — main + short-lived branches + PRs |
Multiple supported release versions |
| GitLab Flow |
Teams needing environment branches (staging, production) |
Teams doing continuous deployment |
| GitFlow |
Versioned software with multiple supported releases |
Continuous delivery — Driessen himself (2020): "adopt a simpler workflow" |
Feature Flags
Feature flags decouple deployment from release. MUST use them when incomplete features need to ship to production.
| Flag Type |
Purpose |
Lifetime |
| Release Toggle |
Hide incomplete features in production |
Days to weeks — remove after launch |
| Ops Toggle |
Runtime circuit breakers and operational controls |
Permanent or long-lived |
| Experiment Toggle |
A/B testing and gradual rollout |
Days to weeks — remove after decision |
| Permission Toggle |
Feature access by user segment (beta, premium) |
Long-lived |
- MUST remove release toggles promptly after the feature is fully launched
- SHOULD track all active flags and assign cleanup owners
Commit Messages
Conventional Commits Format
<type>(scope): description
[optional body]
[optional footer(s)]
Core types and their SemVer mapping:
| Type |
SemVer |
Purpose |
feat |
MINOR |
New user-facing functionality |
fix |
PATCH |
Bug fix |
feat! or BREAKING CHANGE: footer |
MAJOR |
Breaking API change |
docs |
— |
Documentation only |
style |
— |
Formatting, whitespace (no logic change) |
refactor |
— |
Code restructuring (no behavior change) |
perf |
PATCH |
Performance improvement |
test |
— |
Adding or correcting tests |
build |
— |
Build system or dependency changes |
ci |
— |
CI configuration changes |
chore |
— |
Other maintenance (no production code) |
revert |
— |
Reverts a previous commit |
Chris Beams' 7 Rules
- Separate subject from body with a blank line
- Limit subject to 50 characters
- Capitalize the subject line
- Do not end the subject with a period
- Use imperative mood — "Add feature" not "Added feature" or "Adds feature"
- Wrap body at 72 characters
- Body explains what and why, not how
Rules
- MUST use imperative mood in subject: the commit message completes the sentence "If applied, this commit will..."
- MUST make each commit atomic — one logical change that compiles and passes tests independently
- MUST NOT mix unrelated changes in a single commit (formatting + feature + bug fix)
- SHOULD use Conventional Commits format for automated changelog and versioning
- SHOULD include a body for non-trivial changes explaining WHY, not WHAT
Pull Requests
Size Matters
| PR Size |
Review Time |
Defect Detection |
Recommendation |
| < 200 lines |
Fast (~30 min) |
Highest (~40% more defects found) |
Ideal |
| 200–400 lines |
Moderate |
Good |
Acceptable |
| 400–1000 lines |
Slow |
Declining |
Split if possible |
| > 1000 lines |
Very slow |
Drops by ~70% |
MUST split |
Rules
- SHOULD keep PRs under 200 lines of changed code
- MUST include a clear description: context, what changed, why, how to test
- SHOULD use PR templates to ensure consistent descriptions
- MUST NOT submit PRs with failing CI checks
- SHOULD separate refactoring from feature changes — refactoring PRs reviewed differently than feature PRs
Stacked PRs
For features too large for a single small PR, use stacked PRs — a chain of small dependent PRs that build on each other.
- Break the feature into sequential, independently reviewable increments
- Each PR in the stack targets the previous PR's branch (or main for the first)
- Review and merge bottom-up
- Tools: Graphite, ghstack, git-branchless
Git Hooks
Client-Side Hooks
| Hook |
Stage |
Purpose |
Tooling |
pre-commit |
Before commit is created |
Lint, format, type-check staged files |
lint-staged, prettier, eslint |
commit-msg |
After message is entered |
Validate conventional commit format |
commitlint |
pre-push |
Before push to remote |
Run tests, check for secrets |
jest, detect-secrets |
prepare-commit-msg |
Before editor opens |
Pre-populate commit template |
commitizen |
Hook Management Tools
| Tool |
Ecosystem |
Key Feature |
| Husky |
Node.js |
Simple setup with package.json scripts |
| pre-commit |
Python (language-agnostic) |
Large plugin ecosystem, runs hooks in isolation |
| Lefthook |
Go binary (no runtime dependency) |
Parallel execution, fast, no Node required |
Typical Hook Pipeline
pre-commit:
1. lint-staged (format + lint only changed files)
2. type-check (TypeScript, mypy)
3. detect-secrets (prevent accidental credential commits)
commit-msg:
1. commitlint (validate Conventional Commits format)
pre-push:
1. test suite (unit tests, fast integration tests)
Automated Versioning and Release
Conventional Commits enable fully automated semantic versioning:
| Tool |
Approach |
Best For |
| semantic-release |
Fully automated: version, changelog, publish on merge |
CI/CD pipelines with continuous release |
| release-please (Google) |
Creates and maintains release PRs; merge to release |
Teams wanting human approval before release; monorepo support |
| changesets |
Developers describe changes; bot creates release PR |
Monorepos with multiple packages |
| commitizen |
Interactive CLI for crafting conventional commits |
Teams onboarding to conventional commits |
DORA Metrics Connection
The Accelerate research (Forsgren, Humble, Kim) shows four key metrics that distinguish high-performing teams:
| Metric |
Elite Performance |
Connection to Git Practices |
| Lead Time for Changes |
< 1 hour |
Small PRs, trunk-based development, CI/CD |
| Deployment Frequency |
Multiple per day |
Feature flags, automated release |
| Change Failure Rate |
0–15% |
Atomic commits, comprehensive tests, small PRs |
| Time to Restore Service |
< 1 hour |
Fast rollback via revert commits, feature flag kill switches |
Checklist
When setting up or reviewing Git workflows, verify:
Key References
| Book |
Author(s) |
Publisher |
Year |
| Pro Git (2nd ed.) |
Scott Chacon, Ben Straub |
Apress |
2014 |
| Head First Git |
Raju Gandhi |
O'Reilly |
2022 |
| Continuous Delivery |
Jez Humble, David Farley |
Addison-Wesley |
2010 |
| The DevOps Handbook (2nd ed.) |
Kim, Humble, Debois, Willis, Forsgren |
IT Revolution |
2021 |
| Accelerate |
Forsgren, Humble, Kim |
IT Revolution |
2018 |
| Software Engineering at Google |
Winters, Manshreck, Wright |
O'Reilly |
2020 |