The “Pre-Receive Hook Declined” Nightmare: How to Resolve Git Conflicts When Force-Pushing is…
Picture this: It’s late afternoon, your feature branch is complete, and you’re ready to merge your pull request. You open the PR only to…
The “Pre-Receive Hook Declined” Nightmare: How to Resolve Git Conflicts When Force-Pushing is Disabled
Picture this: It’s late afternoon, your feature branch is complete, and you’re ready to merge your pull request. You open the PR only to see the dreaded red warning: This branch has conflicts that must be resolved.
Instinctively, you pull up your terminal, run git rebase origin/release/v3.4.0, locate the conflicting files, clean up the markers, and get ready to update your remote branch. You confidently type:
git push --force-with-lease
You hit Enter, expecting a clean state and a green merge button. Instead, your terminal screen flashes red with a frustrating block of text:
remote: Force-pushing to this repository has been disabled
! [remote rejected] feature/user-auth -> feature/user-auth (pre-receive hook declined)
error: failed to push some refs to 'ssh://github.com/your-org/your-repo.git'
Game over.
If you work in a modern enterprise environment (using GitHub Enterprise, Bitbucket/Stash, or GitLab), you have likely run face-first into this security wall.
In this article, we’ll unpack exactly why this happens, why your usual “rebase-and-force-push” workflow is blocked, and look at the step-by-step “Golden Path” to resolve your conflicts cleanly — without ever needing a force-push.
Why Enterprise Repos Block Force-Pushing (And Why It’s Actually a Good Thing)
First, let’s clear the air: your DevOps team didn’t set this up just to make your life difficult.
When you rebase a branch, Git takes your commits and “re-plays” them on top of the target branch. This process actually deletes your old commits and replaces them with brand-new ones that have completely different hashes. Because you are rewriting history, Git won’t let you push normally; you have to use a force push (-f or --force-with-lease).
In a collaborative enterprise repo, force-pushing is highly dangerous. If a colleague pulled your branch, made a change, and pushed it while you were rebasing, a force push would permanently wipe out their work.
To prevent this, repository admins enable pre-receive hooks that block force-pushing entirely. Your history must remain strictly additive.
Enter the “Standard Merge”: The Savior of Locked-Down Repos
If we can’t rewrite history (rebase), we must add to it. We do this using a Standard Merge.
Instead of moving your commits to the top of the release branch, a merge pulls the release branch into your feature branch and wraps the integration up in a single, clean Merge Commit. No rewritten history, no force-pushing required.
Here is the step-by-step recipe to rescue your branch.
Step 1: Discard the Stalled Rebase (The Clean Slate)
If your terminal is currently stuck in the middle of a rebase, we need to abort it and reset our local files to match what’s on the remote server.
# Fetch the latest updates from the remote server
git fetch origin
# Force your local branch to match the remote server exactly
git reset --hard origin/feature/user-auth
⚠️ Warning:
git reset --hardwill discard any uncommitted local changes. Make sure your local workspace is clean before running this!
Step 2: Merge the Target Branch Into Your Branch
Now, we explicitly merge the target branch (the one you are trying to merge into, like a release or main branch) into your current working branch.
git merge origin/release/v3.4.0
Git will attempt to auto-merge what it can, but it will pause on files modified in both branches:
CONFLICT (content): Merge conflict in config/default.json
Automatic merge failed; fix conflicts and then commit the result.
Step 3: Resolve the Conflicts (Mind the HEAD!)
Open the conflicting files in your editor (VS Code, IntelliJ, or your preferred IDE). You will see Git’s conflict markers:
<<<<<<< HEAD
"TIMEOUT_MS": 5000, (<- This is YOUR branch's code)
=======
"TIMEOUT_MS": 10000, (<- This is the TARGET branch's code)
>>>>>>> origin/release/v3.4.0
💡 Crucial Git Tip: HEAD behaves differently in Merges vs. Rebases!
- During a Rebase,
HEADrefers to the target branch you are rebasing onto. - During a Merge,
HEADrefers to your active feature branch.
Because we are doing a Merge, the top section (HEAD) contains the code you wrote in your feature branch. The bottom section contains the incoming changes from the target release branch.
To resolve the conflict:
- Delete the conflict markers (
<<<<<<<,=======,>>>>>>>). - Keep the code you want (usually your feature branch’s code, or a combination of both if required).
- Ensure the spacing, syntax, and formatting remain intact.
Your final file should look clean:
"TIMEOUT_MS": 5000,
Step 4: Stage, Commit, and Push Normally
Now that the files are clean, we simply commit the resolution and push it. Because this adds a new commit instead of rewriting the past, a normal git push is all you need.
# 1. Stage the resolved files
git add config/default.json
# 2. Commit the merge resolution
git commit -m "Merge branch 'release/v3.4.0' into feature/user-auth and resolve conflicts"
# 3. Push normally! (No force flags!)
git push
Your terminal will show a beautiful success message:
To ssh://github.com/your-org/your-repo.git
c0f243c..294c6eb feature/user-auth -> feature/user-auth
The Verdict: Rebase vs. Merge in the Real World
While “clean git history” advocates love rebasing because it keeps commit graphs perfectly linear, the reality of working in a secure enterprise ecosystem requires adaptability.
Using git merge to pull target branches into your feature branch:
- Keeps your work safe from being overwritten.
- Respects enterprise pre-receive security hooks.
- Keeps a clear, auditable trail of when and how conflicts were resolved.
The next time your terminal shouts at you with a blocked force-push, don’t panic. Abort the rebase, merge the target, resolve the code, and push normally. Your PR (and your DevOps team) will thank you!
Did this save you from a Git headache? Let me know in the comments below, and don’t forget to clap if this helped you out!
메타데이터
- post_id
- a5ae0696d57d
- slug
- the-pre-receive-hook-declined-nightmare-how-to-resolve-git-conflicts-when-force-pushing-is-a5ae0696d57d
- url
- https://medium.com/@ramesh516390/the-pre-receive-hook-declined-nightmare-how-to-resolve-git-conflicts-when-force-pushing-is-a5ae0696d57d
- canonical_url
- https://medium.com/@ramesh516390/the-pre-receive-hook-declined-nightmare-how-to-resolve-git-conflicts-when-force-pushing-is-a5ae0696d57d
- author_url
- https://medium.com/@ramesh516390
- status
- ok
- fetched_at
- 2026-06-26 03:39:16