Git Workflow for Teams -- Branching, PRs, and Merge Strategies That Actually Work
Git Workflow for Teams -- Branching, PRs, and Merge Strategies That Actually Work
Every team that uses Git eventually runs into the same problems. Merge conflicts that take hours to resolve. A main branch that is broken half the time. Nobody knows which branch has the latest working code. Pull requests that sit open for weeks.
These are not Git problems. They are workflow problems. This guide covers branching strategies, pull request practices, and merge approaches that keep teams moving fast without breaking things.
Choosing a Branching Strategy
There is no single "best" branching strategy. The right one depends on your team size, release cadence, and how much process you can tolerate.
Trunk-Based Development
Best for: Small teams (2-8 developers), continuous deployment, teams that deploy multiple times per day.
The idea is simple. Everyone commits to a single branch (main/trunk), either directly or through very short-lived feature branches that last hours, not days.
Rules:
- •Feature branches live for less than 24 hours
- •Every commit to main must pass CI
- •Use feature flags instead of long-lived branches for incomplete features
- •Keep changes small -- one logical change per commit
Advantages:
- •Almost zero merge conflicts
- •Always-deployable main branch
- •Forces small, reviewable changes
- •No "integration hell" when merging long-lived branches
GitHub Flow
Best for: Medium teams (5-20 developers), projects that deploy frequently but want code review on every change.
GitHub Flow adds one layer on top of trunk-based development: every change goes through a pull request.
Rules:
- •Main is always deployable
- •Create a feature branch from main for every change
- •Open a pull request when the work is ready for review
- •After review and CI passes, merge to main
- •Deploy from main
This is what most modern teams use. It is simple enough that everyone follows it, but structured enough that nothing sneaks into main without review.
GitFlow
Best for: Large teams, projects with scheduled releases, mobile apps that go through app store review.
GitFlow uses multiple long-lived branches: main, develop, feature branches, release branches, and hotfix branches. It provides structure for teams that cannot deploy continuously.
Rules:
- •Main always contains production-ready code
- •Develop is the integration branch for features
- •Feature branches are created from develop and merged back into develop
- •Release branches are created from develop when preparing for a release
- •Hotfix branches are created from main for emergency fixes
The downside: GitFlow is complex. Most teams that adopt it end up simplifying it over time because the overhead of managing all those branches outweighs the benefits.
Branch Naming Conventions
Consistent branch names make it easy to understand what a branch does at a glance. Pick a convention and enforce it:
feature/add-user-authentication
fix/login-page-crash-on-empty-email
chore/update-dependencies
docs/add-api-documentation
refactor/simplify-payment-processing
The pattern is: type/short-description-with-hyphens
Common prefixes:
- •feature/ -- new functionality
- •fix/ -- bug fixes
- •chore/ -- maintenance, dependency updates, CI changes
- •docs/ -- documentation changes
- •refactor/ -- code restructuring without behavior changes
- •test/ -- adding or updating tests
Include the ticket number if your team uses a project tracker:
feature/PROJ-123-add-user-authentication
fix/PROJ-456-login-crash
Writing Good Pull Requests
A pull request is not just a code delivery mechanism. It is a communication tool. Good PRs make reviews faster, reduce back-and-forth, and create a useful history.
The Title
Keep it under 72 characters. Start with a verb. Be specific.
Bad: "Updates", "Fix bug", "Changes to auth"
Good: "Add email verification to signup flow", "Fix crash when user submits empty form", "Replace bcrypt with argon2 for password hashing"
The Description
Every PR description should answer three questions:
- 1What does this change do?
- 2Why is this change needed?
- 3How can the reviewer test it?
A simple template:
> ## What
> Added rate limiting to the /api/login endpoint.
>
> ## Why
> We were getting hit with brute force attempts. This limits each IP to 5 attempts per minute.
>
> ## How to Test
> 1. Start the server locally
> 2. Hit /api/login more than 5 times in a minute
> 3. Verify you get a 429 response on the 6th attempt
Keep PRs Small
The most important rule of pull requests: keep them small. Research consistently shows that review quality drops dramatically as PR size increases.
- •Under 200 lines: reviewed carefully, merged quickly
- •200-500 lines: reviewed with decreasing attention
- •Over 500 lines: skimmed at best, rubber-stamped at worst
If your feature requires more than 500 lines, break it into multiple PRs. Ship the data model first, then the API, then the UI.
Code Review Best Practices
For Reviewers
- •Review within 24 hours. Stale PRs kill momentum. If you cannot review today, say so and suggest another reviewer.
- •Focus on what matters. Logic errors, security issues, and architectural problems are worth discussing. Nitpicking variable names and formatting is not (use a linter for that).
- •Ask questions instead of making demands. "What happens if this API call times out?" is better than "Add error handling here."
- •Approve with comments. If you have minor suggestions that do not block the PR, approve it and note them as optional. Do not block PRs over style preferences.
For Authors
- •Self-review before requesting review. Read your own diff. You will catch half the issues yourself.
- •Respond to every comment. Even if the response is "Done" or "Good point, fixed." Unanswered comments create ambiguity.
- •Do not take feedback personally. Code review is about the code, not about you. A suggestion to restructure something is not a judgment of your abilities.
Merge Strategies
Merge Commit (git merge --no-ff)
Creates a merge commit that preserves the entire branch history. Your git log shows exactly when branches were created and merged.
Best for: Teams that want a detailed, accurate history of how code was developed.
Squash and Merge
Combines all commits in the branch into a single commit on main. The individual commits in the feature branch disappear from main's history.
Best for: Teams that want a clean, linear main branch history. Every commit on main represents one complete feature or fix.
Rebase and Merge
Replays the commits from the feature branch on top of main, creating a linear history without a merge commit. Each commit is preserved individually.
Best for: Teams that want a linear history but also want to preserve individual commits within a feature.
Which Should You Use?
- •Squash and merge is the most popular choice for most teams. It keeps main clean and makes reverts easy -- one commit equals one feature.
- •Merge commits work well for teams that want to preserve detailed development history.
- •Rebase and merge is for teams that are disciplined about making each commit meaningful and self-contained.
Pick one strategy and use it consistently across the team.
Handling Merge Conflicts
Merge conflicts are inevitable when multiple people work on the same codebase. Here is how to handle them efficiently:
Prevention
- •Pull from main frequently. The longer your branch lives, the more likely conflicts become.
- •Communicate with your team. If two people are editing the same file, coordinate.
- •Keep PRs small. Smaller changes mean smaller conflict surfaces.
Resolution
When you hit a conflict:
> git fetch origin
> git rebase origin/main
Git will pause at each conflict. Open the conflicting file, and you will see:
> <<<<<<< HEAD
> your changes
> =======
> their changes
> >>>>>>> origin/main
Resolve it by keeping the correct code, removing the conflict markers, then:
> git add the-file.ts
> git rebase --continue
If the conflict is too complex, you can always abort:
> git rebase --abort
Tools That Help
- •VS Code has excellent built-in merge conflict resolution. Click "Accept Current Change", "Accept Incoming Change", or "Accept Both Changes."
- •git rerere (reuse recorded resolution) remembers how you resolved a conflict and automatically applies the same resolution if it comes up again. Enable it with: git config --global rerere.enabled true
Protecting Your Main Branch
Set up branch protection rules in GitHub/GitLab to prevent accidental damage to main:
- •Require pull request reviews -- at least one approval before merging
- •Require CI to pass -- no merging if tests fail
- •Require branches to be up to date -- force rebasing before merge to catch integration issues
- •Restrict force pushes -- nobody should force push to main, ever
- •Require signed commits -- optional, but adds accountability
Git Hooks for Quality
Git hooks run scripts automatically at specific points in the Git workflow. Use them to catch problems before they reach the PR:
- •pre-commit -- run linters and formatters on staged files
- •commit-msg -- enforce commit message conventions
- •pre-push -- run tests before pushing
Use a tool like Husky (Node.js) or pre-commit (Python) to manage hooks across the team. These tools install hooks from a config file in your repo, so everyone gets the same checks automatically.
The One Rule
If you remember nothing else from this guide, remember this: keep your branches short-lived and your pull requests small. Every problem in team Git workflows -- merge conflicts, stale PRs, broken main, lost code -- traces back to branches that live too long and changes that are too large.
For more developer productivity guides, check out our blog and explore our free developer tools.