Git workflow for teams: the daily habits a shared repo runs on
A branching strategy is a map; a workflow is how you actually walk it. Two teams can both say “we use GitHub Flow” and have completely different days. One ships calmly, the other drowns in merge conflicts, half-finished reviews, and a commit log nobody can read six months later.
The difference is rarely the tooling. It’s a handful of habits, repeated. Here’s the loop I teach every engineer I mentor, from the moment they branch to the moment their work lands on main.
Branch from an up-to-date main, name it for a human
Half of all conflicts are born at the very first command, when someone branches off a stale main. Pull first, always.
git switch main
git pull --ff-only
git switch -c feat/transfer-retry
Use a short, conventional prefix so anyone scanning the branch list knows what they’re looking at: feat/… for features, fix/… for bug fixes, chore/… for housekeeping. Keep the branch scoped to one thing. “Add transfer retry” is a branch. “Q3 improvements” is a swamp.
Write commits for the person debugging this at 2am
That person is usually you. A commit message has two jobs: say what changed in the subject, and why in the body. The diff already shows the how.
Conventional Commits give this a small, machine-readable grammar, type(scope): subject, which also powers automatic changelogs and version bumps.
feat(payments): retry failed top-ups with exponential backoff
A flaky gateway was dropping ~2% of top-ups on the first attempt.
Retries now back off 1s/2s/4s before surfacing an error to the user.
Closes #482
Common types: feat, fix, refactor, chore, docs, test. Keep the subject under about 50 characters, in the imperative mood (“add”, not “added”).
Small, described, and green before you ask for eyes
A pull request is a request for someone’s time. Respect it by making the PR easy to say yes to: keep it small (a few hundred lines beats a few thousand), write a description that explains the why and how to test it, and make sure CI is green before you tag a reviewer.
A good PR description answers three questions in a few lines: what does this change, why now, and how did you verify it? Screenshots for UI, a one-line repro for bug fixes. The reviewer should never have to reverse-engineer your intent from the diff.
Review the code, support the coder
Code review is one of the highest-leverage habits a team has. It’s where bugs die young and where knowledge spreads. It only works if both sides play their part.
- As the author: keep it small, respond to every comment (even a “done”), and don’t take feedback on the code as feedback on you.
- As the reviewer: be timely. A PR sitting unreviewed for two days blocks a person. Comment on what matters, and distinguish “this is a bug” from “I’d prefer”. Approve when it’s good enough to ship, not when it’s how you’d have written it.
Update your branch with rebase; never rebase what others have pulled
While your PR is open, main keeps moving. Pull those changes into your branch before the gap grows. Rebasing replays your commits on top of the latest main, keeping history linear and conflicts small:
git switch feat/transfer-retry
git fetch origin
git rebase origin/main
# resolve any conflicts, then update the PR safely
git push --force-with-lease
Note --force-with-lease, not --force. It refuses to clobber the remote if someone else pushed in the meantime. That safety catch matters.
Merge commit, squash, or rebase: pick on purpose
How a PR lands shapes your history for good. Three options, three different shapes:
Most product teams I’ve worked with standardise on squash merge: each PR becomes exactly one tidy commit on main, the messy WIP history disappears, and reverting a feature is a single git revert. Choose merge commits when the individual commits are meaningful and worth preserving. Choose rebase-merge when you want a strictly linear history and your commits are already atomic.
| Merge commit | Squash | Rebase merge | |
|---|---|---|---|
| History shape | Branch preserved + merge node | One commit per PR | Linear, no merge node |
| Easy to revert? | The whole merge, yes | Yes, one commit | Per commit |
| Log readability | Shows true branching | Cleanest summary | Clean, detailed |
| Best when… | Branch context matters | Default for most teams | Commits are already atomic |
Whatever you pick, enforce it with branch protection: no direct pushes to main, required reviews, and required green CI. The rule that can be bypassed at 5pm on a Friday is the rule that will be.
How should this PR land?
Choosing a merge style
None of this is about Git trivia. It’s about keeping changes small, history honest, and your teammates unblocked. Get these six habits into muscle memory and the tool disappears, which is the point.
Not sure which branching model these habits sit inside? Start with Git branching strategies that scale.
Cited sources