patternModerate
Force-push blocked: land a rebased branch via a new branch + fresh PR
Viewed 0 times
force push deniednon-fast-forward rejectedCONFLICTING mergeablesuperseded pull requestgit restore vs checkoutrebase onto moved main
Error Messages
Problem
You rebase a feature branch onto an updated main and resolve the conflicts, but the environment blocks
git push --force, git push --force-with-lease, and git reset --hard via permission rules or branch protection. The local branch has now diverged from its remote tracking branch, so an ordinary push is rejected as non-fast-forward. The existing PR still shows the pre-rebase commits and reports CONFLICTING, and every obvious escape hatch is denied. It looks like you must either abandon the rebase or get the restriction lifted.Solution
Do not fight the restriction. Push the rebased commits under a NEW branch name and re-point the PR:
After a squash-merge the result on main is identical to what a force-push would have produced, because a squash discards branch topology anyway. The only cost is one closed PR, which the "superseded by" comment makes self-explanatory.
Related:
<parameter name="why">Permission layers and branch-protection rules deny commands by name and flags, not by intent.
<parameter name="context">Any repo with branch protection, a sandboxed agent with a git command allowlist, or a corporate policy that forbids history rewrites on shared remotes. Comes up whenever a long-running feature branch has to catch up to a main that moved.
git branch feature/x-rebasedat the rebased HEAD (creating a branch is never blocked).git push -u origin feature/x-rebased- an ordinary push, since that remote ref does not exist yet.gh pr create --base main --head feature/x-rebasedwith the original description plus a short note on how the conflicts were resolved.gh pr close <old-pr> --comment "Superseded by #N - same work rebased onto main."- Merge the new PR, then delete the stale local branches.
After a squash-merge the result on main is identical to what a force-push would have produced, because a squash discards branch topology anyway. The only cost is one closed PR, which the "superseded by" comment makes self-explanatory.
Related:
git restore <file> works when git checkout -- <file> is blocked. Restrictions typically target the multi-purpose destructive commands (checkout, reset) rather than the narrow modern equivalents.</solution><parameter name="why">Permission layers and branch-protection rules deny commands by name and flags, not by intent.
push --force is blocked because it can destroy remote history; pushing a brand-new ref cannot destroy anything, so it passes the same filter. The rebased commits already exist locally and are perfectly valid objects - the only thing missing is a ref that points at them without overwriting an existing one.</why><parameter name="context">Any repo with branch protection, a sandboxed agent with a git command allowlist, or a corporate policy that forbids history rewrites on shared remotes. Comes up whenever a long-running feature branch has to catch up to a main that moved.
Gotchas
- Check whether the old branch was already merged before closing its PR - closing discards it, so confirm the new branch actually contains every commit (
git log --oneline old..newshould be empty). - Squash-merge makes this equivalent; with a plain merge commit you get a slightly noisier graph, though still correct.
- Verify mergeability after pushing -
gh pr view N --json mergeable,mergeStateStatusmay report UNKNOWN for a few seconds while the host computes it. Sleep and re-check rather than concluding it failed. gh pr mergecan exit silently with no output on success; confirm withgh pr view N --json state,mergedAtinstead of trusting empty output.
Revisions (0)
No revisions yet.