The Problem with Git Chaos
Small teams often start with everyone committing directly to main. It works until it doesn't: broken builds, merge conflicts, and the dreaded "who wrote this?" blame game. You don't need a heavyweight process like GitFlow, but you do need a lightweight workflow that keeps the shared branch stable and reviews painless.
Here's a workflow I've used on teams of 2 to 10 people. It's simple, explicit, and handles most real-world scenarios without ceremony.
The Core Rules
-
mainis always deployable. No direct pushes. Ever. - Every change goes through a feature branch and a pull request.
- Branch names describe intent:
feature/,fix/,chore/. - Keep branches short-lived (max a couple of days).
- Rebase before merging, but don't rewrite shared history.
That's it. The rest is mechanics.
Setting Up the Basics
First, protect main on your Git host (GitHub, GitLab, Bitbucket). Require at least one approval and passing CI. This is non-negotiable.
Next, establish a consistent branching convention. I like:
feature/add-login-page
fix/typo-in-footer
chore/update-dependencies
Use slashes, not dots. It keeps things tidy in your branch list.
The Daily Loop
Here's the routine each developer follows, step by step.
1. Start from a fresh main
git checkout main
git pull origin main
git checkout -b feature/my-change
Always pull before branching. This reduces merge conflicts later.
2. Make small, focused commits
Commit often with clear messages. Use the imperative mood: "Add validation", not "added stuff".
git add .
git commit -m "Add email validation to signup form"
3. Push and open a PR early
Don't wait until the feature is perfect. Push a branch with a single commit and open a draft PR. This gives your team visibility and lets you ask for early feedback.
git push -u origin feature/my-change
4. Keep your branch up to date
While you work, main moves. Rebase your branch onto the latest main regularly. This keeps the history linear and avoids messy merge commits.
git fetch origin
git rebase origin/main
If you hit conflicts, resolve them, then continue:
git add .
git rebase --continue
5. Merge with a squash
When the PR is approved and CI passes, merge using squash and merge. This collapses all your tiny commits into one clean commit on main.
# On GitHub/GitLab, click the squash merge button
# Or locally:
git checkout main
git pull origin main
git merge --squash feature/my-change
git commit -m "Add login page"
git push origin main
git branch -d feature/my-change
Squashing keeps main history readable. Each commit is a complete, working unit.
Handling Common Situations
Hotfixes
A hotfix is just a branch, but it gets priority. Create fix/critical-bug from main, fix, test, and merge immediately. Don't wait for other features.
Large features
If a feature takes longer than a few days, consider merging it behind a feature flag. This keeps the branch from drifting too far from main. You can also split it into smaller PRs that each merge into main without breaking anything.
Multiple people on the same feature
Rarely needed, but if two people must work on the same feature, have them share a branch. They can push to the same remote branch and coordinate. But in most cases, split the work into separate branches.
Why This Works
- Stable main: No one can break the shared branch accidentally.
- Code review: Every change gets a second pair of eyes.
-
Clean history: Squash merging keeps
mainreadable. - Low overhead: No complex rules, no release branches, no backporting.
You can adopt this workflow in an afternoon. It doesn't require new tools or training, just discipline. Once your team gets used to it, you'll wonder how you ever worked without it.
Final Tips
- Write good PR descriptions. Include what and why, not just how.
- Use templates for PRs if your Git host supports them.
- Don't be afraid to comment on your own PR. It helps reviewers.
- If a rebase gets messy,
git rebase --abortand try again. You can always squash at the end.
This workflow isn't revolutionary. It's just solid practice, scaled down to what small teams actually need. Give it a try, and adjust the details to fit your team's rhythm. The goal is to spend less time fighting Git and more time shipping software.
Top comments (0)