Writing a team merge policy Jump to heading
Every team eventually has the merge-versus-rebase argument, usually in a pull request thread at the worst possible moment. Without a written policy, each person follows their own habits: one squash-merges, another rebase-merges, a third merges with commits, someone force-pushes a shared branch. History becomes an inconsistent mix that serves nobody, and the argument repeats with every new team member. A merge policy settles it: a page that states how branches stay current, how pull requests land on main, when history may be rewritten, and how each rule is enforced. It does not need to be long β the useful ones fit on one screen β but it needs to be explicit and backed by settings, so it is followed by default. This page walks through writing one, within merge vs rebase decision matrix.
When to use this approach Jump to heading
- Merge methods on main are inconsistent, or the team keeps re-debating them.
- New team members ask how to update their branch or how to merge, and get different answers.
- A force-push or a rebase of a shared branch has caused lost work.
- You have weighed the options, for example in the real cost of requiring linear history, and need to write the outcome down.
Step 1 β Answer the four questions the policy must cover Jump to heading
A merge policy answers four questions. Leave out the rest.
Step 2 β Draft it in a few lines Jump to heading
Write the policy as a short document in the repository, next to the contributing guide, with each rule followed by a one-sentence reason. Reasons keep the policy from being re-litigated, because the next person can see what was weighed.
# Merge policy
**Landing on main:** squash merge only. *Why:* one commit per change keeps main readable and bisectable; we do not rely on per-commit history inside pull requests.
**Staying current:** your branch, your choice β rebase onto main or merge main in. Shared branches: merge main in only. *Why:* rebasing shared branches forces collaborators to reset.
**Rewriting history:** allowed on branches only you use, with `git push --force-with-lease`. Never on main, release branches or shared branches. *Why:* rewrites of shared history lose other people's work.
**Enforcement:** squash-only and no force-push on main are repository settings; everything else is convention, checked in review. Step 3 β Enforce what can be enforced in settings Jump to heading
Policies followed by default are policies followed. Encode every rule you can as a repository setting or ruleset, so the wrong action is unavailable rather than merely discouraged.
# Squash merge only, with the PR title as the commit message
gh api -X PATCH "repos/$OWNER/$REPO" \
-F allow_squash_merge=true -F allow_merge_commit=false -F allow_rebase_merge=false \
-f squash_merge_commit_title=PR_TITLE -f squash_merge_commit_message=PR_BODY
# No force-push or deletion on main and release branches (ruleset rules)
gh api "repos/$OWNER/$REPO/rulesets" --jq '.[] | {name, enforcement}' Step 4 β Set safe local defaults for everyone Jump to heading
Some rules live on developer machines: how git pull integrates, how force-pushes are done. Ship those in the teamβs shared Git configuration.
# team.gitconfig
[pull]
rebase = true # rebase local unpushed work on pull; never creates merge commits
[rebase]
autoStash = true
updateRefs = true
[push]
default = simple
[alias]
pushf = push --force-with-lease --force-if-includes Distribution is covered in shipping a team gitconfig with includeIf, and the pull setting in configuring git pull --rebase safely for a team.
Step 5 β Roll it out and listen Jump to heading
Propose the policy as a pull request, so the team can comment on it like code. Once merged, apply the settings, announce it with a link, and revisit after a few weeks: are people working around a rule? That usually means the rule or its reason needs updating.
gh pr create --title "Add merge policy" --body-file docs/merge-policy.md Step 6 β Keep it current Jump to heading
When the team or the codebase changes β a monorepo migration, signed-commit requirements, a merge queue β revisit the policy. A merge policy that describes a workflow the team no longer uses is worse than none, because new members follow it.
Validation checklist Jump to heading
Frequently Asked Questions Jump to heading
Should every repository in an organisation share one policy? Jump to heading
A shared default policy with per-repository exceptions works well. Libraries that preserve per-commit history and services that squash-merge may legitimately differ; record the difference where people will see it.
What if a team member strongly disagrees with the policy? Jump to heading
The pull request is the place for it. A policy with reasons can be argued with on its merits, and changed if the argument holds; that is better than silent non-compliance.
Does the policy need to cover commit messages? Jump to heading
Only where the merge method affects them β for example, that squash commit messages come from the pull request title. Message conventions themselves belong in their own guide, such as enforcing subject line length and format.
Related Jump to heading
- Merge vs Rebase Decision Matrix β the parent topic.
- Squash vs Merge vs Rebase Decision Matrix β the landing choice in depth.
- Managing Repository Permissions as Code β keeping settings consistent across repositories.
- Reading History with --first-parent β if the policy keeps merge commits.