If you've ever tried to implement GitFlow at a startup or small team, you know how it goes. You set up develop branches and release branches and hotfix branches, and within a week everyone is confused and you're spending more time managing Git than writing code.
I've been there. And after working with teams of various sizes over the years, I've learned that the best Git workflow is the simplest one that actually works for your team. Here's what I've found effective for teams of 2-10 developers.
Why GitFlow Doesn't Work for Small Teams
GitFlow was designed for managing complex release schedules with multiple versions in production simultaneously. If you're deploying continuously (like most modern web apps do) or you have a small team, GitFlow adds unnecessary complexity.
Think about it: you're maintaining at least two long-lived branches (main and develop), plus feature branches, plus release branches when you want to deploy. That's a lot of branches and a lot of merging for a team that could just be pushing to main.
The Simple Approach: Trunk-Based Development
For most small teams, trunk-based development works better. Here's the idea:
The Core Workflow
Everyone works off of main. Feature branches are short-lived (ideally merged same day or next day). Deploy from main frequently. That's basically it.
This sounds scary if you're used to having a develop branch as a "safety net," but with modern tools it works surprisingly well. The key is that your feature branches should be small and your main branch should always be deployable.
How It Works in Practice
# Start a new feature
git checkout main
git pull
git checkout -b feature/user-avatars
# Do your work, commit often
git add .
git commit -m "Add avatar upload component"
git commit -m "Add avatar storage service"
git commit -m "Connect avatar to user profile"
# Push and create PR
git push -u origin feature/user-avatars
# After review and CI passes, merge to main
# (Usually done through GitHub/GitLab UI)
# Delete the branch after merge
git checkout main
git pull
git branch -d feature/user-avatars
The key difference from GitFlow is that there's no develop branch. Features go straight to main after review. This forces you to keep changes small and keep the main branch stable.
Making It Work: The Prerequisites
Trunk-based development requires some things to be in place:
Automated tests: You need a CI pipeline that runs tests on every PR. If tests pass and code review is approved, you should feel confident merging to main. Without tests, you're just hoping nothing breaks.
Code review: Every PR gets reviewed before merge. This catches issues and spreads knowledge across the team. Keep reviews quick - if a PR sits for days, you're doing it wrong.
Feature flags: For larger features that take multiple days, use feature flags to hide incomplete work. The code is in main, but users don't see it until you flip the flag.
Real talk: If you don't have CI/CD and code review in place yet, setting those up is more important than worrying about branching strategies. A simple workflow with no automation is still going to cause problems.
When You Need More Structure
Sometimes you do need a release branch. Maybe you have a mobile app with app store review times, or you're managing multiple versions for different clients. In that case, GitHub Flow is a reasonable middle ground:
GitHub Flow
Main is always deployable. Create feature branches from main and PR back to main. When you want to release, create a release branch from main. Hotfixes go to the release branch and get merged back to main.
This gives you a place to prepare releases without the full complexity of GitFlow. You only create release branches when you actually need them, not as part of the regular workflow.
Commit Messages That Don't Suck
Whatever workflow you use, good commit messages save time. Here's what works:
- Start with a verb: "Add," "Fix," "Update," "Remove"
- Keep the first line under 50 characters
- Add a blank line and details if needed
- Reference issue numbers when relevant
Fix user avatar upload failing for PNG files
The image processing library was rejecting PNGs with alpha
channels. Added explicit handling for transparency.
Fixes #234
Bad commit messages like "fix bug" or "updates" or just "wip" make it impossible to understand history later. Take 30 seconds to write something useful.
My Actual Recommendations
Team of 2-5 devs: Trunk-based development. Keep it simple. You can talk to each other easily, so you don't need process to communicate.
Team of 5-10 devs: Trunk-based with slightly longer feature branches (2-3 days max). More emphasis on code review quality.
Need release management: GitHub Flow. Only add release branches when you actually have a release cycle that requires it.
Complex product with multiple versions: Consider GitFlow, but honestly, this usually means your product has gotten complex enough that you have bigger problems to solve.
The Meta-Point
The best Git workflow is one your whole team understands and follows consistently. A "simpler" workflow that nobody follows is worse than a "complex" one that everyone uses correctly.
Start simple. Add complexity only when you have a specific problem that requires it. And remember that Git is a tool - if you're spending more time thinking about Git than about your actual code, something has gone wrong.