git
git push
git configuration
repository management
version control

Is there a way to configure git repository to reject 'git push --force'?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Yes. You can prevent force pushes, but the enforcement has to happen on the remote side, not in each developer's local Git config. A local alias or hook can be bypassed instantly. The real controls are branch protection on hosted platforms or server-side hooks on repositories you administer directly. The rule you are trying to enforce is simple: reject non-fast-forward updates on protected refs.

Understand What Force Push Actually Changes

A normal push moves a branch tip forward. A force push allows the remote branch to be rewritten to a commit that is not a descendant of the old tip.

That is why force push is dangerous in shared branches:

  1. It can discard commits from other people.
  2. It can rewrite published history.
  3. It can break open pull requests or deployment assumptions.

What you want to reject is not literally the --force flag. What you want to reject is the non-fast-forward update that --force enables.

Use Branch Protection on Hosted Git Platforms

If the repository is on GitHub, GitLab, Bitbucket, or a similar platform, the cleanest answer is branch protection. Protect main, master, release branches, or any long-lived shared branch and disable force pushes there.

This approach is better than custom scripting when the platform already supports it because:

  1. It is centralized.
  2. It is visible in the repository settings.
  3. It usually supports exceptions for admins or maintainers if needed.

In hosted environments, branch protection is normally the correct first answer.

Use a Server-Side Hook on Bare Repositories

If you manage the Git server yourself, reject non-fast-forward updates with a pre-receive hook in the bare repository.

Example hooks/pre-receive:

bash
1#!/bin/sh
2
3while read oldrev newrev refname
4do
5    case "$refname" in
6        refs/heads/main|refs/heads/master)
7            if ! git merge-base --is-ancestor "$oldrev" "$newrev"
8            then
9                echo "Rejected non-fast-forward update to $refname"
10                exit 1
11            fi
12            ;;
13    esac
14done
15
16exit 0

Make it executable:

bash
chmod +x hooks/pre-receive

Now pushes that rewrite main or master will be rejected even if the client uses git push --force.

Protect Only the Right Branches

Not every branch needs the same rule. Many teams allow force pushes on short-lived feature branches but reject them on shared branches.

That is why the hook example checks specific refs:

  1. refs/heads/main
  2. refs/heads/master
  3. release branches if desired

This keeps history protection strict where collaboration depends on it without making private branch cleanup impossible.

Do Not Rely on Client-Side Hooks

You can add a client-side pre-push hook that warns or blocks a force push, but it is only advisory because each developer controls their own machine. Any policy that truly matters must be enforced by the remote repository.

Client-side safeguards are fine for ergonomics. They are not a security boundary or collaboration guarantee.

Consider --force-with-lease as a Different Policy

Some teams do not want to ban force pushes entirely. They want to ban unsafe force pushes while allowing careful history rewrites on non-shared branches. In those cases, the cultural rule may be:

  1. Never force push to protected branches.
  2. Use --force-with-lease instead of raw --force on personal branches.

That is a workflow policy, not the same thing as remote rejection, but it is worth distinguishing.

Test the Rule Before Trusting It

After configuring protection or hooks, verify it with a safe test repository:

  1. Create a branch.
  2. Push normally.
  3. Rewrite history locally.
  4. Attempt the force push.

If the push is still accepted, the hook or platform rule is not protecting the ref you think it is.

Common Pitfalls

  • Trying to solve the problem with local Git configuration instead of remote-side enforcement.
  • Blocking only the literal --force flag mentally instead of focusing on non-fast-forward updates.
  • Applying the rule to every branch and making normal feature-branch cleanup needlessly painful.
  • Installing a server-side hook but forgetting to make it executable.
  • Assuming hosted Git platforms require custom scripting when built-in branch protection already exists.

Summary

  • Yes, a repository can be configured to reject force pushes, but the enforcement must be on the remote side.
  • Use branch protection on hosted Git platforms whenever possible.
  • On self-managed bare repositories, reject non-fast-forward updates with a server-side hook.
  • Protect shared branches selectively rather than applying one rule to every ref.
  • Treat client-side hooks as convenience only, not as policy enforcement.

Course illustration
Course illustration