Using GitLab Protected Branches to Stop Accidental Force Pushes
Learn how GitLab protected branches enforce merge‑only workflows, block force pushes, and what trade‑offs to watch for.
31 Aug 2026, 00:19 UTC

When a force push slips into production
Imagine a developer accidentally runs git push --force on the main branch while trying to clean up a local feature branch. In a repository without safeguards, that command overwrites the remote history, potentially erasing recent commits and breaking downstream pipelines.
How GitLab protected branches enforce safety
GitLab lets you mark a branch (or a pattern like main or release/*) as protected. When a branch is protected:
- Direct pushes and force pushes are rejected unless the actor has the
Maintainerrole (or higher). - Pipeline jobs that listen on
pushevents are not triggered; they run only when a merge request is merged, ensuring code review. - Access rules are evaluated against the project’s role matrix, so
Developercontributors must open a merge request instead of pushing directly.
Configuring a protected branch
- Navigate to Project → Settings → Repository → Protected branches.
- In the Branch name field, enter the exact branch name or a wildcard pattern (e.g.,
mainorproduction/*). - Set Allowed to push to Maintainers (or a specific group) and Allowed to merge to Maintainers or Developers as needed.
- Leave Allow force pushes unchecked unless you explicitly need it.
- Click Protect to save.
Worked example: verifying the block
Assume you have a Developer account and the main branch is protected as described above.
# Clone the repository (if you haven’t already)
git clone https://gitlab.com/<group>/<project>.git
cd <project>
# Ensure you are on the protected branch
git checkout main
git pull origin main
# Attempt a force push – this should be rejected
git push --force origin main
Expected output (error message):
remote: GitLab: You are not allowed to push code to this protected branch.
To https://gitlab.com/<group>/<project>.git
! [remote rejected] main -> main (pre-receive hook declined)
error: failed to push some refs to 'https://gitlab.com/<group>/<project>.git'
If you see the above, the protection is working. No remote state is changed.
Trade‑offs and limitations
- Over‑protecting branches can block legitimate hot‑fix pushes. In such cases, a Maintainer can temporarily unprotect the branch or grant the
Allowed to push permission to a specific role for the duration of the fix. - Jobs that rely on
pushtriggers (e.g., auto‑deploy on every push tomain) will not run on protected branches. You must migrate those jobs to run on merge request pipelines or usemergetriggers instead. - Protected‑branch settings apply only to the refs they match; wildcard patterns must be tested to avoid unintentionally protecting development branches.
- List all branches that currently have protection (Settings → Repository → Protected branches).
- Confirm that the Allowed to push list matches the team’s release process.
- Run the force‑push test shown above on a non‑critical protected branch to verify the error appears.
- Adjust any CI/CD jobs that depend on push events to use merge‑request pipelines.
Actionable next steps
Review your project’s branch protection matrix:
By keeping only the essential branches protected and validating the behavior with a simple push test, you gain a reliable safety net against accidental history rewrites while keeping your delivery flow predictable.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.