GitHub Best Practices: Branch Strategy, PRs, and Repo Organization
GitHub best practices for engineering teams — branch naming conventions, pull request workflows, code review culture, and repository organization that scales.

James Ross Jr.
Strategic Systems Architect & Enterprise Software Developer
GitHub Best Practices: Branch Strategy, PRs, and Repo Organization
A Git workflow is one of those things that seems unimportant until the team grows to three people and suddenly merge conflicts are daily, nobody can track which features are in which release, and the main branch breaks every other day because someone pushed untested code directly.
The practices I describe here are not theoretical. They are the patterns I have seen work across teams ranging from three engineers to fifty. They are also not dogma — adapt them to your context.
Branch Strategy: Trunk-Based Development
There are three common branch strategies: Git Flow, GitHub Flow, and trunk-based development. My recommendation is trunk-based development for most teams, and here is why.
Git Flow has long-lived develop, release, and hotfix branches. It made sense when deployments were scheduled events. For teams shipping to production multiple times a day, the overhead of maintaining multiple long-lived branches and merging between them adds friction without corresponding benefit.
GitHub Flow is simple: one main branch, short-lived feature branches, merge to main. This works well but can lead to integration problems when feature branches live for more than a few days.
Trunk-based development takes GitHub Flow further: main is always deployable, feature branches are extremely short-lived (1-3 days maximum), and features that are not ready for users are hidden behind feature flags rather than on a separate branch. Integration happens continuously, not at a "release merge" moment.
The discipline trunk-based development requires: feature flags for incomplete features, a CI pipeline that must pass before merging, and a culture where nobody ships untested code because main is always live.
Branch Naming Conventions
Whatever strategy you use, consistent branch naming makes your repository navigable:
feature/TICKET-123-user-authentication
fix/TICKET-456-login-redirect-loop
chore/update-dependencies
docs/api-documentation
refactor/payment-service-cleanup
The prefix indicates the type of change. The ticket number (if you use one) provides traceability to your issue tracker. The description makes the branch's purpose clear from the name alone.
Enforce this with a Git hook or a GitHub Actions workflow that validates branch names:
- name: Validate branch name
run: |
BRANCH_NAME="${{ github.head_ref }}"
if ! echo "$BRANCH_NAME" | grep -qE "^(feature|fix|chore|docs|refactor)/"; then
echo "Branch name '$BRANCH_NAME' does not follow naming convention"
exit 1
fi
Pull Request Discipline
The pull request is where code review happens. The quality of your PR process directly affects the quality of code in production. A few principles I enforce:
Small, focused PRs. A PR that touches 15 files and changes 800 lines gets cursory reviews because reviewing it thoroughly would take three hours. A PR that changes 3 files and 100 lines gets real review because it is possible to understand completely. Aim for PRs that take under 30 minutes to review thoroughly. If your change requires more scope, break it into sequential PRs.
PRs have a clear description. Your PR description should explain what the change does, why it is being made, and how to test it. Reviewers should not need to read every line of code to understand the purpose of a PR.
A PR template enforces this:
## What
Brief description of the change.
## Why
Context for why this change is being made. Link to issue/ticket.
## How to Test
1. Steps to verify the change works correctly
2. Edge cases to check
## Screenshots (if UI change)
## Checklist
- [ ] Tests added/updated
- [ ] Documentation updated if needed
- [ ] Migrations applied if needed
Check this template in at .github/PULL_REQUEST_TEMPLATE.md. GitHub automatically populates the PR description with it.
Require CI to pass before merge. Configure branch protection rules on main to require your CI workflow to pass. Under Settings > Branches > Branch protection rules, enable "Require status checks to pass before merging." Select your CI workflow as a required check. This is the mechanical enforcement of "main is always green."
Require at least one code review. Also in branch protection rules, enable "Require a pull request before merging" and "Require approvals: 1." Solo developers can use a self-review workflow or require no approvals, but once you have more than one engineer, human code review is a quality gate worth the friction.
Code Review Culture
The technical side of code review is straightforward: check for correctness, performance issues, security vulnerabilities, test coverage, and adherence to your patterns. The cultural side is what determines whether code review is useful.
Code review feedback should be about code, not about the author. "This query will do a sequential scan on large tables — an index on user_id would improve this significantly" is helpful feedback. "Why would you write it this way?" is not.
Distinguish between required changes and suggestions. Mark required changes clearly. Flag stylistic preferences or alternatives as non-blocking. Reviewers who block merges on personal style preferences slow the team down without improving quality.
Respond to review comments promptly. A PR that sits waiting for the author's response to a comment for three days creates merge conflicts and loses its reviewer's context. Treat open PRs as work in progress until they merge.
Repository Organization
For a single-team project, a straightforward structure is usually best:
myapp/
├── .github/
│ ├── workflows/ # GitHub Actions
│ ├── PULL_REQUEST_TEMPLATE.md
│ └── CODEOWNERS
├── src/ # Application code
├── tests/ # Test files
├── docs/ # Documentation
├── docker-compose.yml
├── .env.example
└── README.md
CODEOWNERS is underused. It maps file paths to the GitHub users or teams who must review changes to those files. Changes to your authentication module should require review from someone who owns that code:
# .github/CODEOWNERS
src/auth/ @myorg/auth-team
src/payments/ @myorg/payment-team
infrastructure/ @myorg/devops-team
When a PR touches a file covered by CODEOWNERS, GitHub automatically requests a review from the owner. This ensures the right people review changes to sensitive or complex code.
Managing Issues and Projects
Use GitHub Issues for bug tracking and feature requests. Create issue templates for different types:
<!-- .github/ISSUE_TEMPLATE/bug_report.md -->
---
name: Bug Report
about: Report a reproducible bug
labels: bug
---
## Description
What went wrong?
## Steps to Reproduce
1.
2.
## Expected Behavior
## Actual Behavior
## Environment
- Browser/OS:
- Application version:
Link issues to PRs with Fixes #123 in the PR description. GitHub automatically closes the issue when the PR merges and creates a traceability link in both directions.
GitHub Projects is viable for kanban-style sprint planning if you are already living in GitHub. For more sophisticated project management, Jira or Linear may serve you better, but the overhead of maintaining both GitHub Issues and an external tracker is real — choose one as the source of truth.
Protected Main Branch Configuration
The complete branch protection configuration for main:
- Require a pull request before merging
- Require approvals: 1 (or 2 for larger teams)
- Dismiss stale pull request approvals when new commits are pushed
- Require review from Code Owners
- Require status checks to pass before merging (select your CI checks)
- Require branches to be up to date before merging
- Do not allow force pushes
- Do not allow deletions
This configuration enforces that every change to main goes through review, passes CI, and is current with main at the time of merge. It is the mechanical backbone of a professional Git workflow.
If you want help establishing Git and GitHub workflows for your team, or want a second opinion on your current process, book a session at https://calendly.com/jamesrossjr.